@Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || AssociationKey.class != o.getClass()) {
      return false;
    }

    AssociationKey that = (AssociationKey) o;

    // order of comparison matters on performance:
    if (!metadata.getTable().equals(that.metadata.getTable())) {
      return false;
    }

    // Probably incorrect - comparing Object[] arrays with Arrays.equals
    if (!Arrays.equals(columnValues, that.columnValues)) {
      return false;
    }
    if (!Arrays.equals(metadata.getColumnNames(), that.metadata.getColumnNames())) {
      return false;
    }

    return true;
  }
  public AssociationKey(
      AssociationKeyMetadata metadata, Object[] columnValues, EntityKey entityKey) {
    this.metadata = metadata;
    if (metadata.getColumnNames().length != columnValues.length) {
      throw new AssertionFailure("Column names do not match column values");
    }
    this.columnValues = columnValues;
    this.entityKey = entityKey;

    this.hashCode = metadata.hashCode() * 31 + Arrays.hashCode(columnValues);
  }
 @Override
 public String toString() {
   final StringBuilder sb = new StringBuilder();
   sb.append("AssociationKey(");
   sb.append(getTable());
   sb.append(") [");
   int i = 0;
   for (String column : metadata.getColumnNames()) {
     sb.append(column).append("=").append(columnValues[i]);
     i++;
     if (i < metadata.getColumnNames().length) {
       sb.append(", ");
     }
   }
   sb.append("]");
   return sb.toString();
 }
 /**
  * The columns identifying the association.
  *
  * <p>For example, in a many to many association, the row key will look like:
  *
  * <pre>
  * RowKey{table='AccountOwner_BankAccount', columnNames=[owners_id, bankAccounts_id], columnValues=[...]},
  * </pre>
  *
  * the association key will be something like:
  *
  * <pre>
  * AssociationKey{table='AccountOwner_BankAccount', columnNames=[owners_id], columnValues=[...]},
  * </pre>
  */
 public String[] getColumnNames() {
   return metadata.getColumnNames();
 }
 /** Returns the table name of this key. */
 public String getTable() {
   return metadata.getTable();
 }