diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractName.java b/jOOQ/src/main/java/org/jooq/impl/AbstractName.java index 2b10a82f46..c0d8627711 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractName.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractName.java @@ -362,10 +362,9 @@ implements // XXX: Object API // ------------------------------------------------------------------------ + // [#13499] Enforce an optimised implementation @Override - public int hashCode() { - return Arrays.hashCode(getName()); - } + public abstract int hashCode(); @Override public boolean equals(Object that) { diff --git a/jOOQ/src/main/java/org/jooq/impl/LazyName.java b/jOOQ/src/main/java/org/jooq/impl/LazyName.java index 63d1f8bf1a..e4cd94d311 100644 --- a/jOOQ/src/main/java/org/jooq/impl/LazyName.java +++ b/jOOQ/src/main/java/org/jooq/impl/LazyName.java @@ -150,4 +150,13 @@ final class LazyName extends AbstractName { + + // ------------------------------------------------------------------------ + // XXX: Object API + // ------------------------------------------------------------------------ + + @Override + public int hashCode() { + return name().hashCode(); + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/QualifiedName.java b/jOOQ/src/main/java/org/jooq/impl/QualifiedName.java index e989761a86..62d1c2c7ab 100644 --- a/jOOQ/src/main/java/org/jooq/impl/QualifiedName.java +++ b/jOOQ/src/main/java/org/jooq/impl/QualifiedName.java @@ -44,6 +44,8 @@ import static org.jooq.impl.Tools.anyMatch; import static org.jooq.impl.Tools.map; import static org.jooq.impl.Tools.stringLiteral; +import java.util.function.Supplier; + import org.jooq.Context; import org.jooq.Name; import org.jooq.tools.StringUtils; @@ -66,7 +68,7 @@ final class QualifiedName extends AbstractName { } QualifiedName(Name[] qualifiedName) { - this.qualifiedName = last(nonEmpty(qualifiedName)); + this(last(nonEmpty(qualifiedName))); } private QualifiedName(UnqualifiedName[] qualifiedName) { @@ -251,4 +253,27 @@ final class QualifiedName extends AbstractName { public final Name[] parts() { return qualifiedName.clone(); } + + // ------------------------------------------------------------------------ + // XXX: Object API + // ------------------------------------------------------------------------ + + // The assumption is that race conditions for the assignment are + // acceptable because the computation is idempotent, so memory + // barriers or synchronization aren't necessary. + private transient Integer hash; + + @Override + public int hashCode() { + if (hash == null) { + int h = 1; + + for (int i = 0; i < qualifiedName.length; i++) + h = 31 * h + qualifiedName[i].name.hashCode(); + + hash = h; + } + + return hash; + } } diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 90f74e65e8..3fee3cbc6d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -6371,6 +6371,24 @@ final class Tools { return result; } + static final Supplier cached(Supplier s) { + return new Supplier<>() { + + // The assumption is that race conditions for the assignment are + // acceptable because the computation is idempotent, so memory + // barriers or synchronization isn't necessary. + transient T cached; + + @Override + public T get() { + if (cached == null) + cached = s.get(); + + return cached; + } + }; + } + /** * A base implementation for {@link EmbeddableTableField} flattening * iterators with a default implementation for {@link Iterator#remove()} for diff --git a/jOOQ/src/main/java/org/jooq/impl/UnqualifiedName.java b/jOOQ/src/main/java/org/jooq/impl/UnqualifiedName.java index ac1cfa5764..97ea82aee0 100644 --- a/jOOQ/src/main/java/org/jooq/impl/UnqualifiedName.java +++ b/jOOQ/src/main/java/org/jooq/impl/UnqualifiedName.java @@ -44,6 +44,8 @@ import static org.jooq.Name.Quoted.UNQUOTED; // ... import static org.jooq.impl.Tools.stringLiteral; +import java.util.Arrays; + import org.jooq.Context; import org.jooq.Name; import org.jooq.conf.RenderQuotedNames; @@ -57,8 +59,8 @@ import org.jooq.tools.StringUtils; */ final class UnqualifiedName extends AbstractName { - private final String name; - private final Quoted quoted; + final String name; + final Quoted quoted; UnqualifiedName(String name) { this(name, DEFAULT); @@ -160,4 +162,16 @@ final class UnqualifiedName extends AbstractName { public final Name[] parts() { return new Name[] { this }; } + + // ------------------------------------------------------------------------ + // XXX: Object API + // ------------------------------------------------------------------------ + + @Override + public int hashCode() { + + // [#13499] Since QualifiedName and UnqualifiedName can be equal, both + // need the same hashCode() computation + return 31 * 1 + name.hashCode(); + } }