@@ -0,0 +1,2466 @@
+package dev.kkorolyov.sqlob.util;%0A%0Aimport dev.kkorolyov.sqlob.annotation.Column;%0Aimport dev.kkorolyov.sqlob.annotation.Table;%0Aimport dev.kkorolyov.sqlob.annotation.Transient;%0A%0Aimport java.lang.reflect.Field;%0Aimport java.lang.reflect.Modifier;%0Aimport java.util.Arrays;%0Aimport java.util.stream.Stream;%0A%0A/**%0A * Provides static utility methods for translating properties between Java and SQL.%0A */%0Apublic final class PersistenceHelper %7B%0A%09private PersistenceHelper() %7B%7D%0A%0A%09/**%0A%09 * Returns the name of the table associated with class %7B@code c%7D.%0A%09 * Table name defaults to the name of the class, but may be customized with the %7B@link Table%7D annotation.%0A%09 * @return name of table matching %7B@code c%7D%0A%09 * @see Table%0A%09 */%0A%09public static String getName(Class%3C?%3E c) %7B%0A%09%09Table override = c.getAnnotation(Table.class);%0A%09%09if (override != null && override.value().length() %3C= 0) throw new IllegalArgumentException(c + %22 has a Table annotation with an empty name%22);%0A%0A%09%09return (override == null) ? c.getSimpleName() : override.value();%0A%09%7D%0A%09/**%0A%09 * Returns the name of the column associated with field %7B@code f%7D.%0A%09 * Column name defaults to the name of the field, but may be customized with the %7B@link Column%7D annotation.%0A%09 * @return name of column matching %7B@code f%7D%0A%09 * @see Column%0A%09 */%0A%09public static String getName(Field f) %7B%0A%09%09Column override = f.getAnnotation(Column.class);%0A%09%09if (override != null && override.value().length() %3C= 0) throw new IllegalArgumentException(f + %22 has a Column annotation with an empty name%22);%0A%0A%09%09return (override == null) ? f.getName() : override.value();%0A%09%7D%0A%0A%09/** @return all declared fields in %7B@code c%7D matching the requirements of %7B@link #isPersistable(Field)%7D with their accessibility restrictions removed */%0A%09public static Stream%3CField%3E getPersistableFields(Class%3C?%3E c) %7B%0A%09%09return Arrays.stream(c.getDeclaredFields())%0A%09%09%09%09.filter(PersistenceHelper::isPersistable)%0A%09%09%09%09.peek(f -%3E f.setAccessible(true));%0A%09%7D%0A%09/**%0A%09 * Checks whether %7B@code f%7D is a %22persistable%22 field.%0A%09 * A field is deemed persistable if it is%0A%09 * %3Cpre%3E%0A%09 *   - Not static%0A%09 *   - Not transient%0A%09 *   - Not %7B@link Transient%7D%0A%09 *   - Not synthetic%0A%09 * %3C/pre%3E%0A%09 * @param f field to test%0A%09 * @return whether %7B@code f%7D is a persistable field%0A%09 */%0A%09public static boolean isPersistable(Field f) %7B%0A%09%09int modifiers = f.getModifiers();%0A%09%09return !Modifier.isStatic(modifiers)%0A%09%09%09%09&& !Modifier.isTransient(modifiers)%0A%09%09%09%09&& f.getAnnotation(Transient.class) == null%0A%09%09%09%09&& !f.isSynthetic();%0A%09%7D%0A%7D%0A

Handle collections: Add PersistenceHelper