diff --git a/build.gradle b/build.gradle index 710a7b5..f9c9b42 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'tech.nevets.osql4j' -version '1.1.3' +version '1.2.0' sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 diff --git a/src/main/java/tech/nevets/osql4j/ClassUtils.java b/src/main/java/tech/nevets/osql4j/ClassUtils.java new file mode 100644 index 0000000..5a99287 --- /dev/null +++ b/src/main/java/tech/nevets/osql4j/ClassUtils.java @@ -0,0 +1,39 @@ +package tech.nevets.osql4j; + +public class ClassUtils { + + public static Class forName(String name) throws ClassNotFoundException { + switch (name) { + case "int" -> { + return int.class; + } + case "short" -> { + return short.class; + } + case "long" -> { + return long.class; + } + case "float" -> { + return float.class; + } + case "double" -> { + return double.class; + } + case "boolean" -> { + return boolean.class; + } + case "byte" -> { + return byte.class; + } + case "byte[]" -> { + return byte[].class; + } + case "char" -> { + return char.class; + } + default -> { + return Class.forName(name); + } + } + } +} diff --git a/src/main/java/tech/nevets/osql4j/SQLConnection.java b/src/main/java/tech/nevets/osql4j/SQLConnection.java index e1bd06f..7d63d44 100644 --- a/src/main/java/tech/nevets/osql4j/SQLConnection.java +++ b/src/main/java/tech/nevets/osql4j/SQLConnection.java @@ -132,6 +132,136 @@ public class SQLConnection { createTable(); } + /** + * Raw access to sql execute method. See {@link java.sql.Statement#execute(String)} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @param sql see above link + * @throws SQLException see above link + */ + public boolean execute(String sql) throws SQLException { + return statement.execute(sql); + } + + /** + * Raw access to sql execute method. See {@link java.sql.Statement#execute(String, String[])} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @param sql see above link + * @throws SQLException see above link + */ + public boolean execute(String sql, String[] columnNames) throws SQLException { + return statement.execute(sql, columnNames); + } + + /** + * Raw access to sql execute method. See {@link java.sql.Statement#execute(String, int[])} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @param sql see above link + * @throws SQLException see above link + */ + public boolean execute(String sql, int[] columnIndexes) throws SQLException { + return statement.execute(sql, columnIndexes); + } + + /** + * Raw access to sql execute method. See {@link java.sql.Statement#execute(String, int)} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @param sql see above link + * @throws SQLException see above link + */ + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + return statement.execute(sql, autoGeneratedKeys); + } + + /** + * Raw access to sql executeUpdate method. See {@link java.sql.Statement#executeUpdate(String)} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @param sql see above link + * @throws SQLException see above link + */ + public int executeUpdate(String sql) throws SQLException { + return statement.executeUpdate(sql); + } + + /** + * Raw access to sql executeUpdate method. See {@link java.sql.Statement#executeUpdate(String, String[])} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @param sql see above link + * @throws SQLException see above link + */ + public int executeUpdate(String sql, String[] columnNames) throws SQLException { + return statement.executeUpdate(sql, columnNames); + } + + /** + * Raw access to sql executeUpdate method. See {@link java.sql.Statement#executeUpdate(String, int[])} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @param sql see above link + * @throws SQLException see above link + */ + public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { + return statement.executeUpdate(sql, columnIndexes); + } + + /** + * Raw access to sql executeUpdate method. See {@link java.sql.Statement#executeUpdate(String, int)} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @param sql see above link + * @throws SQLException see above link + */ + public int executeUpdates(String sql, int autoGeneratedKeys) throws SQLException { + return statement.executeUpdate(sql, autoGeneratedKeys); + } + + /** + * Raw access to sql executeQuery method. See {@link java.sql.Statement#executeQuery(String)} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @param sql see above link + * @throws SQLException see above link + */ + public ResultSet executeQuery(String sql) throws SQLException { + return statement.executeQuery(sql); + } + + /** + * Raw access to sql addBatch method. See {@link java.sql.Statement#addBatch(String)} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @param sql see above link + * @throws SQLException see above link + */ + public void addBatch(String sql) throws SQLException { + statement.addBatch(sql); + } + + /** + * Raw access to sql clearBatch method. See {@link java.sql.Statement#clearBatch()} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @throws SQLException see above link + */ + public void clearBatch() throws SQLException { + statement.clearBatch(); + } + + /** + *Raw access to sql executeBatch method. See {@link Statement#executeBatch()} for more info + *
Only use if you know what you are doing! + *
USE AT YOUR OWN RISK + * @throws SQLException see above link + */ + public int[] executeBatch() throws SQLException { + return statement.executeBatch(); + } + public void writeObject(T object) { try { List fieldValues = getFieldValues(object); @@ -170,7 +300,7 @@ public class SQLConnection { String sql = "SELECT * FROM " + clazz.getSimpleName() + " WHERE " + column + "=" + id + ";"; ResultSet results = statement.executeQuery(sql); while (results.next()) { - objects.add(getFromDatabase(results)); + objects.add(getObjectFromDatabase(results)); } } catch (final Exception e) { System.out.println("Error parsing object from database..."); @@ -185,7 +315,7 @@ public class SQLConnection { String sql = "SELECT * FROM " + clazz.getSimpleName() + ";"; ResultSet results = statement.executeQuery(sql); while (results.next()) { - objects.add(getFromDatabase(results)); + objects.add(getObjectFromDatabase(results)); } } catch (final SQLException e) { System.out.println("Error parsing objects from database..."); @@ -244,57 +374,74 @@ public class SQLConnection { return obj; } - private T getFromDatabase(ResultSet results) { + private T getObjectFromDatabase(ResultSet resultSet) { + T object; try { - T object = clazz.getConstructor().newInstance(); - for (int i = 0; i < fields.size(); i++) { - String fieldName = fields.get(i).getName(); - String fieldType = fields.get(i).getType().getName(); - Field objectField = null; - for (Class c = clazz; c != null; c = c.getSuperclass()) { - try { - objectField = object.getClass().getDeclaredField(fieldName); - } catch (NoSuchFieldException e) { - continue; - } - break; - } - if (objectField == null) { - break; + List> classFieldTypeLists = new ArrayList<>(); + for (Class c = clazz; c != null; c = c.getSuperclass()) { + List fieldTypeList = new ArrayList<>(); + Field[] declaredFields = c.getDeclaredFields(); + for (Field declaredField : declaredFields) { + fieldTypeList.add(declaredField.getType().getName()); } + classFieldTypeLists.add(fieldTypeList); + } - objectField.setAccessible(true); - - switch (fieldType) { - case "boolean", "java.lang.Boolean" -> objectField.setBoolean(object, results.getBoolean(i + 1)); - case "byte", "java.lang.Byte" -> objectField.setByte(object, results.getByte(i + 1)); - case "byte[]", "java.lang.Byte[]" -> objectField.set(object, results.getBytes(i + 1)); - case "double", "java.lang.Double" -> objectField.setDouble(object, results.getFloat(i + 1)); - case "float", "java.lang.Float" -> objectField.setFloat(object, results.getFloat(i + 1)); - case "int", "java.lang.Integer" -> objectField.setInt(object, results.getInt(i + 1)); - case "long", "java.lang.Long" -> objectField.setLong(object, results.getLong(i + 1)); - case "short", "java.lang.Short" -> objectField.setShort(object, results.getShort(i + 1)); - case "java.lang.String" -> objectField.set(object, results.getString(i + 1)); - case "java.math.BigDecimal" -> objectField.set(object, results.getBigDecimal(i + 1)); - case "java.sql.Date" -> objectField.set(object, results.getDate(i + 1)); - case "java.sql.Time" -> objectField.set(object, results.getTime(i + 1)); - case "java.sql.TimeStamp" -> objectField.set(object, results.getTimestamp(i + 1)); + List> finalFieldTypeList = new ArrayList<>(); + for (int i = classFieldTypeLists.size() - 1; i >= 0; i--) { + for (String fieldType : classFieldTypeLists.get(i)) { + finalFieldTypeList.add(ClassUtils.forName(fieldType)); } } - return object; + Class[] typeClassArray = new Class[finalFieldTypeList.size()]; + for (int i = 0; i < finalFieldTypeList.size(); i++) { + typeClassArray[i] = finalFieldTypeList.get(i); + } + + List params = new ArrayList<>(); + for (int i = 0; i < fields.size(); i++) { + switch (fields.get(i).getType().getName()) { + case "boolean", "java.lang.Boolean" -> params.add(resultSet.getBoolean(i + 1)); + case "byte", "java.lang.Byte" -> params.add(resultSet.getByte(i + 1)); + case "byte[]", "java.lang.Byte[]" -> params.add(resultSet.getBytes(i + 1)); + case "double", "java.lang.Double", "float", "java.lang.Float" -> params.add(resultSet.getFloat(i + 1)); + case "int", "java.lang.Integer" -> params.add(resultSet.getInt(i + 1)); + case "long", "java.lang.Long" -> params.add(resultSet.getLong(i + 1)); + case "short", "java.lang.Short" -> params.add(resultSet.getShort(i + 1)); + case "java.lang.String" -> params.add(resultSet.getString(i + 1)); + case "java.math.BigDecimal" -> params.add(resultSet.getBigDecimal(i + 1)); + case "java.sql.Date" -> params.add(resultSet.getDate(i + 1)); + case "java.sql.Time" -> params.add(resultSet.getTime(i + 1)); + case "java.sql.TimeStamp" -> params.add(resultSet.getTimestamp(i + 1)); + } + } + Object[] paramsArray = new Object[params.size()]; + for (int i = 0; i < params.size(); i++) { + paramsArray[i] = params.get(i); + } + + object = clazz.getConstructor(typeClassArray).newInstance(paramsArray); } catch (final Exception e) { System.out.println("Error parsing object from database result"); e.printStackTrace(); - return null; + object = null; } + return object; } private List getFields() { - List fieldsList = new ArrayList<>(); + List> classFieldLists = new ArrayList<>(); for (Class c = clazz; c != null; c = c.getSuperclass()) { - fieldsList.addAll(Arrays.asList(c.getDeclaredFields())); + List fieldList = new ArrayList<>(List.of(c.getDeclaredFields())); + classFieldLists.add(fieldList); } - return fieldsList; + + List fieldList = new ArrayList<>(); + for (int i = classFieldLists.size() - 1; i >= 0; i--) { + fieldList.addAll(classFieldLists.get(i)); + } + + return fieldList; } private String getFieldArray() { diff --git a/src/test/java/NewDBFetchTest.java b/src/test/java/NewDBFetchTest.java new file mode 100644 index 0000000..974990e --- /dev/null +++ b/src/test/java/NewDBFetchTest.java @@ -0,0 +1,65 @@ +import examplebeans.Cat; + +import java.lang.reflect.Field; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.List; + +public class NewDBFetchTest { + Class clazz; + + public NewDBFetchTest(Class clazz) { + this.clazz = clazz; + } + + private T getObjectFromDatabase(/*ResultSet resultSet*/) { + T object; + try { + List> classFieldTypeLists = new ArrayList<>(); + for (Class c = clazz; c != null; c = c.getSuperclass()) { + List fieldTypeList = new ArrayList<>(); + Field[] declaredFields = c.getDeclaredFields(); + for (Field declaredField : declaredFields) { + fieldTypeList.add(declaredField.getType().getName()); + } + classFieldTypeLists.add(fieldTypeList); + } + + { // DEBUG + System.out.println("1: ------------------------------"); + for (List strList : classFieldTypeLists) { + for (String str : strList) { + System.out.println(str); + } + } + } // DEBUG + + List finalFieldTypeList = new ArrayList<>(); + for (int i = classFieldTypeLists.size() - 1; i >= 0; i--) { + finalFieldTypeList.addAll(classFieldTypeLists.get(i)); + } + + { //DEBUG + System.out.println("2: ------------------------------"); + for (String str : finalFieldTypeList) { + System.out.println(str); + } + } // DEBUG + + object = null; + } catch (final Exception e) { + System.out.println("Error parsing object from database result"); + e.printStackTrace(); + object = null; + } + return object; + } + + public static void main(String[] args) { + + for (int i = 0; i < 10; i++) { + System.out.println(i); + } + + } +} diff --git a/src/test/java/NewDBTest.java b/src/test/java/NewDBTest.java index 52e486d..7e00675 100644 --- a/src/test/java/NewDBTest.java +++ b/src/test/java/NewDBTest.java @@ -1,11 +1,15 @@ import examplebeans.Cat; import tech.nevets.osql4j.SQLConnection; +import java.math.BigDecimal; + public class NewDBTest { public static void main(String[] args) { + Cat cat = new Cat("Sylvester", 7, "black", BigDecimal.valueOf(3), false); + SQLConnection.setGlobalDBLocation("./database.db"); SQLConnection connection = new SQLConnection<>(Cat.class); - connection.writeObject(new Cat("Fuzzy", 6, "brown", true)); + connection.writeObject(cat); for (Cat animal : connection.getAllObjects()) { System.out.println(animal); diff --git a/src/test/java/ReflectionTest.java b/src/test/java/ReflectionTest.java new file mode 100644 index 0000000..9723e32 --- /dev/null +++ b/src/test/java/ReflectionTest.java @@ -0,0 +1,38 @@ +import examplebeans.Cat; +import tech.nevets.osql4j.ClassUtils; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ReflectionTest { + + public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException { + List> classList = List.of( + ClassUtils.forName("java.lang.String"), + ClassUtils.forName("int"), + ClassUtils.forName("java.lang.String"), + ClassUtils.forName("java.math.BigDecimal"), + ClassUtils.forName("boolean") + ); + Class[] classArray = new Class[classList.size()]; + for (int i = 0; i < classList.size(); i++) { + classArray[i] = classList.get(i); + } + + Constructor catConstructor = Cat.class.getConstructor(classArray); + + Cat cat = catConstructor.newInstance( + "name", + 12, + "brown", + BigDecimal.valueOf(12.42), + false + ); + + System.out.println(cat); + } +} diff --git a/src/test/java/examplebeans/Animal.java b/src/test/java/examplebeans/Animal.java index f391e76..393a6e8 100644 --- a/src/test/java/examplebeans/Animal.java +++ b/src/test/java/examplebeans/Animal.java @@ -2,18 +2,22 @@ package examplebeans; import tech.nevets.osql4j.annotations.SQLSerializable; +import java.math.BigDecimal; + @SQLSerializable public class Animal { private String name; private int age; private String color; + private BigDecimal weight; public Animal() {} - public Animal(String name, int age, String color) { + public Animal(String name, int age, String color, BigDecimal weight) { this.name = name; this.age = age; this.color = color; + this.weight = weight; } public String getName() { @@ -40,8 +44,16 @@ public class Animal { this.color = color; } + public BigDecimal getWeight() { + return weight; + } + + public void setWeight(BigDecimal weight) { + this.weight = weight; + } + @Override public String toString() { - return "(Animal: " + name + ", " + age + ", " + color + ")"; + return "(Animal: " + name + ", " + age + ", " + color + ", " + weight + ")"; } } diff --git a/src/test/java/examplebeans/Cat.java b/src/test/java/examplebeans/Cat.java index fc00aca..0211f81 100644 --- a/src/test/java/examplebeans/Cat.java +++ b/src/test/java/examplebeans/Cat.java @@ -1,17 +1,22 @@ package examplebeans; +import tech.nevets.osql4j.annotations.SQLSerializable; + +import java.math.BigDecimal; + +@SQLSerializable public class Cat extends Animal { private boolean isFerrel; public Cat() {} - public Cat(String name, int age, String color, boolean isFerrel) { - super(name, age, color); + public Cat(String name, int age, String color, BigDecimal weight, boolean isFerrel) { + super(name, age, color, weight); this.isFerrel = isFerrel; } @Override public String toString() { - return "(Cat: " + getName() + ", " + getAge() + ", " + getColor() + ", " + isFerrel + ")"; + return "(Cat: " + getName() + ", " + getAge() + ", " + getColor() + ", " + getWeight() + ", " + isFerrel + ")"; } }