Possibly a question which has been asked before, but as usual the second you mention the word generic you get a thousand answers explaining type erasure. I went through that ph
I think you are a static-typed guy, but lemme try: have you thought about using a dynamic language like groovy for that part?
From your description it seems to me like types are more getting in the way than helping anything.
In groovy you can let the Cell.valVal
be dynamic typed and get an easy transformation around:
class Cell {
String val
def valVal
}
def cell = new Cell(val:"10.0")
cell.valVal = cell.val as BigDecimal
BigDecimal valVal = cell.valVal
assert valVal.class == BigDecimal
assert valVal == 10.0
cell.val = "20"
cell.valVal = cell.val as Integer
Integer valVal2 = cell.valVal
assert valVal2.class == Integer
assert valVal2 == 20
Where as
it's everything needed for the most common transformations. You can add yours too.
If needing to transform other blocks of code, note that java's syntax is valid groovy syntax, except for the do { ... } while()
block
You could try type tokens:
public <T> T getValue(Class<T> cls) {
if (valVal == null) return null;
else {
if (cls.isInstance(valVal)) return cls.cast(valVal);
return null;
}
}
Note, that this does not do any conversion (i.e., you cannot use this method to extract a Double
, if valVal
is an instance of Float
or Integer
).
You should get, btw., a compiler warning about your definition of getValVal
. This is, because the cast cannot be checked at run-time (Java generics work by "erasure", which essentially means, that the generic type parameters are forgotten after compilation), so the generated code is more like:
public Object getValVal() {
return valVal;
}
As you are discovering, there is a limit to what can be expressed using Java's type system, even with generics. Sometimes there are relationships between the types of certain values which you would like to assert using type declarations, but you can't (or perhaps you can, at the cost of excess complexity and long, verbose code). I think the sample code in this post (question and answers) is a good illustration of that.
In this case, the Java compiler could do more type checking if you stored the object/string representation inside the "transformer". (Perhaps you'll have to rethink what it is: maybe it's not just a "transformer".) Put a generic bound on your base Transformer
class, and make that same bound the type of the "object".
As far as getting the value out of the cell, there's no way that compiler type checking will help you there, since the value can be of different types (and you don't know at compile time what type of object will be stored in a given cell).
I believe you could also do something similar to:
public <T> void setObject(Transformer<T> transformer, T object) {}
If the only way to set the transformer and object is through that method, compiler type checking on the arguments will prevent an incompatible transformer/object pair from going into a cell.
If I understand what you're doing, the type of Transformer
which you use is determined solely by the type of object which the cell is holding, is that right? If so, rather than setting the transformer/object together, I would provide a setter for the object only, and do a hash lookup to find the appropriate transformer (using the object type as key). The hash lookup could be done every time the value is set, or when it is converted to a String. Either way would work.
This would naturally make it impossible for the wrong type of Transformer
to be passed in.