diff --git a/build.gradle b/build.gradle index b67c602688..b457d6f03b 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ subprojects { apply plugin: 'maven-publish' group 'ru.tinkoff.qa.neptune' - version '0.1.8-ALPHA' + version '0.1.9-ALPHA' sourceCompatibility = 1.9 targetCompatibility = 1.9 diff --git a/data.base.api/src/main/java/ru/tinkoff/qa/neptune/data/base/api/CompositeKey.java b/data.base.api/src/main/java/ru/tinkoff/qa/neptune/data/base/api/CompositeKey.java new file mode 100644 index 0000000000..0ecee4a538 --- /dev/null +++ b/data.base.api/src/main/java/ru/tinkoff/qa/neptune/data/base/api/CompositeKey.java @@ -0,0 +1,55 @@ +package ru.tinkoff.qa.neptune.data.base.api; + +import java.io.Serializable; +import java.lang.reflect.Field; +import java.util.List; +import java.util.stream.Collectors; + +import static java.lang.reflect.Modifier.isStatic; +import static java.util.Arrays.stream; + +/** + * This class is designed to implement classes of composite key objects. + * It is supposed to be used at the case below + * {@code @PersistenceCapable(table = "TABLE_NAME", objectIdClass = CompositeKeySubclass.class)} + * + * WARNING: it is necessary to override following methods: + *

{@link #hashCode()}

+ *

{@link #equals(Object)}

+ *

{@link #toString()}

+ * + * It is enough + *

+ * {@code 'public int hashCode() { + * return super.hashCode(); + * }'} + *

+ */ +public abstract class CompositeKey extends OrmObject implements Serializable { + + @Override + public int hashCode() { + int result = 0; + Class clazz = this.getClass(); + while (!clazz.equals(Object.class)) { + List fields = stream(clazz.getDeclaredFields()).filter(field -> !isStatic(field.getModifiers())) + .collect(Collectors.toList()); + for (Field f : fields) { + f.setAccessible(true); + try { + Object v = f.get(this); + if (v == null) { + continue; + } + result = result ^ v.hashCode(); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + clazz = clazz.getSuperclass(); + } + + return result; + } +} diff --git a/data.base.api/src/main/java/ru/tinkoff/qa/neptune/data/base/api/OrmObject.java b/data.base.api/src/main/java/ru/tinkoff/qa/neptune/data/base/api/OrmObject.java new file mode 100644 index 0000000000..64a5338c99 --- /dev/null +++ b/data.base.api/src/main/java/ru/tinkoff/qa/neptune/data/base/api/OrmObject.java @@ -0,0 +1,60 @@ +package ru.tinkoff.qa.neptune.data.base.api; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.stream.Collectors; + +import static java.lang.reflect.Modifier.isStatic; +import static java.util.Arrays.stream; +import static java.util.Optional.ofNullable; + +class OrmObject { + + private boolean equalsByFields(Object obj) { + Class clazz = this.getClass(); + while (!clazz.equals(Object.class)) { + List fields = stream(clazz.getDeclaredFields()).filter(field -> !isStatic(field.getModifiers())) + .collect(Collectors.toList()); + for (Field f: fields) { + f.setAccessible(true); + try { + Object v1 = f.get(this); + Object v2 = f.get(obj); + + if (v1 == null && v2 == null) { + continue; + } + + if ((v1 != null && v2 == null) || (v1 == null && v2 != null)) { + return false; + } + + if (v1.equals(v2)) { + continue; + } + + return false; + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + clazz = clazz.getSuperclass(); + } + + return true; + } + + @Override + public boolean equals(Object obj) { + OrmObject toCheck = this; + return ofNullable(obj) + .map(o -> { + if (toCheck == o) { + return true; + } + return toCheck.getClass().equals(obj.getClass()) && + toCheck.equalsByFields(obj); + }) + .orElse(false); + } +} diff --git a/data.base.api/src/main/java/ru/tinkoff/qa/neptune/data/base/api/PersistableObject.java b/data.base.api/src/main/java/ru/tinkoff/qa/neptune/data/base/api/PersistableObject.java index e22c82bc90..52b02a26ff 100644 --- a/data.base.api/src/main/java/ru/tinkoff/qa/neptune/data/base/api/PersistableObject.java +++ b/data.base.api/src/main/java/ru/tinkoff/qa/neptune/data/base/api/PersistableObject.java @@ -2,69 +2,10 @@ import com.google.gson.Gson; -import java.lang.reflect.Field; -import java.util.List; -import java.util.stream.Collectors; - -import static java.lang.reflect.Modifier.isStatic; -import static java.util.Arrays.stream; -import static java.util.Optional.ofNullable; - /** * This abstract class is designed to mark persistable classes. */ -public abstract class PersistableObject implements Cloneable { - - private boolean equalsByFields(Object obj) { - Class clazz = this.getClass(); - while (!clazz.equals(PersistableObject.class)) { - List fields = stream(clazz.getDeclaredFields()).filter(field -> !isStatic(field.getModifiers())) - .collect(Collectors.toList()); - for (Field f: fields) { - f.setAccessible(true); - try { - Object v1 = f.get(this); - Object v2 = f.get(obj); - - if (v1 == null && v2 == null) { - continue; - } - - if ((v1 != null && v2 == null) || (v1 == null && v2 != null)) { - return false; - } - - if (v1.equals(v2)) { - continue; - } - - return false; - } catch (IllegalAccessException e) { - throw new RuntimeException(e.getMessage(), e); - } - } - clazz = clazz.getSuperclass(); - } - - return true; - } - - @Override - public boolean equals(Object obj) { - PersistableObject toCheck = this; - return ofNullable(obj) - .map(o -> { - if (toCheck == o) { - return true; - } - else if (!PersistableObject.class.isAssignableFrom(obj.getClass())) { - return false; - } - return toCheck.getClass().equals(obj.getClass()) && - toCheck.equalsByFields(obj); - }) - .orElse(false); - } +public abstract class PersistableObject extends OrmObject implements Cloneable { @Override public String toString() {