Patch from Zell to ensure that Key objects are only constructed with primary

key fields and also don't leave any out.
This commit is contained in:
Michael Bayne
2007-04-17 17:42:56 +00:00
parent 41d75ff59b
commit e3e515b087
+47 -31
View File
@@ -21,6 +21,7 @@
package com.samskivert.jdbc.depot;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -28,7 +29,9 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.samskivert.jdbc.depot.annotation.Id;
import com.samskivert.jdbc.depot.clause.Where;
import com.samskivert.util.StringUtil;
/**
* A special form of {@link Where} clause that uniquely specifices a single database row and
@@ -68,31 +71,46 @@ public class Key<T extends PersistentRecord> extends Where
/**
* Constructs a new multi-column {@code Key} with the given values.
*
* TODO: There is no reason to store both fields and values here (and doing so probably more
* than doubles the space the key consumes in the cache). The primary key fields are known
* by the DepotMarshaller; we should simply check tha the given indices match those, and
* store the values in the order defined by the DepotMarshaller. The sanity check would be
* welcome in any case. The only problem with this is that we don't currently have access to
* a {@link PersistenceContext}. It may be that we should make this class internal to
* {@link DepotRepository} and only create it ourselves. This would require *lots* more
* convenience methods in {@link DepotRepository} though.
*/
public Key (Class<T> pClass, String[] fields, Comparable[] values)
{
// TODO: make Where an interface so we don't have to do this ugly super call
super(null);
_pClass = pClass;
if (fields.length != values.length) {
throw new IllegalArgumentException("Field and Value arrays must be of equal length.");
}
_pClass = pClass;
_map = new HashMap<String, Comparable>();
// build a local map of field name -> field value
Map<String, Comparable> map = new HashMap<String, Comparable>();
for (int i = 0; i < fields.length; i ++) {
_map.put(fields[i], values[i]);
map.put(fields[i], values[i]);
}
// then introspect on the persistent record and iterate over its actual fields
_fields = new ArrayList<String>(fields.length);
_values = new ArrayList<Comparable>(fields.length);
for (Field field : _pClass.getFields()) {
// look for @Id fields
if (field.getAnnotation(Id.class) != null) {
String fName = field.getName();
// make sure we were provided with a value for this primary key field
if (map.containsKey(fName) == false) {
throw new IllegalArgumentException("Missing value for key field: " + fName);
}
_fields.add(fName);
_values.add(map.get(fName));
map.remove(fName);
}
}
// finally make sure we were not given any fields that are not in fact primary key fields
if (map.size() > 0) {
throw new IllegalArgumentException(
"Non-key columns given: " + StringUtil.join(map.keySet().toArray(), ", "));
}
}
// from QueryClause
public Collection<Class<? extends PersistentRecord>> getClassSet ()
{
@@ -106,15 +124,11 @@ public class Key<T extends PersistentRecord> extends Where
public void appendClause (ConstructedQuery<?> query, StringBuilder builder)
{
builder.append(" where ");
boolean first = true;
for (Map.Entry entry : _map.entrySet()) {
if (first) {
first = false;
} else {
for (int ii = 0; ii < _fields.size(); ii ++) {
if (ii > 0) {
builder.append(" and ");
}
builder.append(entry.getKey());
builder.append(entry.getValue() == null ? " is null " : " = ? ");
builder.append(_fields.get(ii)).append(_values.get(ii) == null ? " is null " : " = ? ");
}
}
@@ -122,9 +136,9 @@ public class Key<T extends PersistentRecord> extends Where
public int bindArguments (PreparedStatement pstmt, int argIdx)
throws SQLException
{
for (Map.Entry entry : _map.entrySet()) {
if (entry.getValue() != null) {
pstmt.setObject(argIdx ++, entry.getValue());
for (int ii = 0; ii < _fields.size(); ii ++) {
if (_values.get(ii) != null) {
pstmt.setObject(argIdx ++, _values.get(ii));
}
}
return argIdx;
@@ -139,7 +153,7 @@ public class Key<T extends PersistentRecord> extends Where
// from CacheKey
public Serializable getCacheKey ()
{
return _map;
return _values;
}
// from CacheInvalidator
@@ -151,7 +165,7 @@ public class Key<T extends PersistentRecord> extends Where
@Override
public int hashCode ()
{
return _pClass.hashCode() + 31 * _map.hashCode();
return _pClass.hashCode() + 31 * _values.hashCode();
}
@Override
@@ -164,20 +178,22 @@ public class Key<T extends PersistentRecord> extends Where
return false;
}
Key other = (Key) obj;
return (_pClass == other._pClass && _map.equals(other._map));
return _pClass == other._pClass && _values.equals(other._values);
}
@Override
public String toString ()
{
StringBuilder builder = new StringBuilder("[Key pClass=" + _pClass.getName());
for (Map.Entry entry : _map.entrySet()) {
builder.append(", ").append(entry.getKey()).append("=").append(entry.getValue());
for (int ii = 0; ii < _fields.size(); ii ++) {
builder.append(", ").append(_fields.get(ii)).append("=").append(_values.get(ii));
}
builder.append("]");
return builder.toString();
}
protected Class<T> _pClass;
protected HashMap<String, Comparable> _map;
protected ArrayList<String> _fields;
protected ArrayList<Comparable> _values;
}