I have the following class
public class DBField<T>
{
protected String fieldName;
protected FieldConverter c;
protected T value;
protected DataObject dataObject;
public T getValue()
{
return value;
}
public void setValue(T value)
{
this.value = value;
}
public DBField(DataObject dataObject, String fieldName, FieldConverter c)
{
this.fieldName = fieldName;
this.c = c;
this.dataObject = dataObject;
}
}
T is supposed to be Boolean, Float, String etc.
protected void ValuesToFields(List<Object> values, List<DBField<?>> fields) throws Exception
{
if (values.size() != fields.size())
throw new Exception("Length does not match.");
for (int i = 0; i < values.size(); i++)
{
Class valueClass = values.get(i).getClass();
Class fieldClass = fields.get(i).getValue().getClass();
if (valueClass.equals(fieldClass))
{
fields.get(i).setValue(values.get(i));
}
else
throw new Exception("type mismatch");
}
}
Object is also supposed to contain Boolean, Float, String etc.
The problem with this code is
fields.get(i).setValue(values.get(i));
The syntax checker tells me I need to cast values.get(i) (to ? i suspect). How do I do this? I already tried valueClass.cast(values.get(i)) but no luck.
In order for your code to be safe, for each
i, the i’th element ofvaluesmust be an instance of the type parameter of theDBFieldthat is the i’th element offields. Your code does not guarantee that this holds, and in fact there is no way to declare them in Java to ensure that this relationship between corresponding elements is true. And due to type erasure, you can’t even check at runtime that the elements are right, because given a field, you don’t know its type parameter. So there must be some unchecked casts, and we must take on faith that the arguments are correct.The simplest thing to do would be to cast each field to
DBField<Object>:This is kind of saying “trust us, we know that this field can take any
Object“, and thus it can take a value of any type. It is kind of lying, because we know there are supposed to be fields whose type parameter is notObject, but since we must make some kind of unchecked cast anyway, this “unsafe cast” is no worse than the other solutions.Alternately, if you don’t want to do this arguably dubious cast, a more “legitimate” way would be to write a private helper method — a “wrapper helper” — which explicitly names the type parameter of the field, allowing us to simply cast to the value to this type:
Note that the cast here is also an unchecked cast. The disadvantage of this method is that it requires the overhead of writing an extra method.
P.S. Your checks with
valueClassandfieldClassare not very good. First of all, if the value of a field is currentlynull, it will cause a null pointer exception. Also, the value of aDBField<T>is any instance ofT, whose actual class may be a subclass ofT; so if you use this to check, it might lead to bad results. It’s probably best ifDBFieldcontains the class object of the class ofT, so it can be used to check. Also, you shouldn’t compare equality with the value’s actual class, since a subclass ofTwould also work, so you should checkfieldClass.isInstance(values.get(i))instead.