I'd like to create a generic enum-based mapper for IBatis. I'm doing this with the below code. This does have compile time errors, which I don't know how to fix. Maybe my solution is just plain wrong (keep in mind the use of IBatis), in such case please suggest something better.
Any help appreciated.
What I want to achieve is to define subsequent mappers as:
public class XEnumTypeHandler extends CommonEnumTypeHandler<X> {
}
The current code:
public class CommonEnumTypeHandler<T extends Enum> implements TypeHandlerCallback {
public void setParameter(ParameterSetter ps, Object o) throws SQLException {
if (o.getClass().isAssignableFrom(**T**)) {
ps.setString(((**T**) o).value().toUpperCase());
} else
throw new SQLException("Excpected ParameterType object than: " + o);
}
public Object getResult(ResultGetter rs) throws SQLException {
Object o = valueOf(rs.getString());
if (o == null)
throw new SQLException("Unknown parameter type: " + rs.getString());
return o;
}
public Object valueOf(String s) {
for (T pt : T.**values()**) {
if (pt.**value()**.equalsIgnoreCase(s))
return pt;
}
return null;
}
}
I've added error markings to the above code, the error messages are in order:
I've solved this issue with the following code:
public class CommonEnumTypeHandler<T extends Enum> implements TypeHandlerCallback {
Class<T> clazz;
public CommonEnumTypeHandler(Class<T> clazz) {
this.clazz = clazz;
}
public void setParameter(ParameterSetter ps, Object o) throws SQLException {
if (o.getClass().isAssignableFrom(clazz)) {
ps.setString(((T) o).name().toUpperCase());
} else
throw new SQLException("Excpected " + clazz + " object than: " + o);
}
public Object getResult(ResultGetter rs) throws SQLException {
Object o = valueOf(rs.getString());
if (o == null)
throw new SQLException("Unknown parameter type: " + rs.getString());
return o;
}
public Object valueOf(String s) {
return Enum.valueOf(clazz, s);
}
}
Inheriting from this class I do:
public class SalesChannelTypeHandler extends CommonEnumTypeHandler<SalesChannel> {
public SalesChannelTypeHandler() {
super(SalesChannel.class);
}
public SalesChannelTypeHandler(Class<SalesChannel> clazz) {
super(clazz);
}
}
Because there is only one instance of each enum constant, it is permissible to use the == operator in place of the equals method when comparing two object references if it is known that at least one of them refers to an enum constant.
There are two ways for making comparison of enum members : equals method uses == operator internally to check if two enum are equal. This means, You can compare Enum using both == and equals method.
As we have learned, we cannot inherit enum classes in Java. However, enum classes can implement interfaces.
enum starts always with 0.
I'm not sure what you're doing (a general overview in words would be nice), but:
isAssignableFrom(T)
(you need a Class
object), and you can't do instanceof T
either (generics are non-reified). You may want to pass Class<T>
type tokens instead.EnumMap
?It's still not clear what is desired, but perhaps it's something along the lines of this:
enum Color { BLACK, WHITE; }
public static void main(String[] args) {
Color c = Enum.valueOf(Color.class, "black".toUpperCase());
System.out.println(c); // prints "BLACK"
}
So we use Enum.valueOf
that takes a type token Class<T extends Enum<T>>
, and ask it for the enum
constant with a given name. valueOf
is NOT case-insensitive, but by conventions, all constants should be in uppercase, so we simply take the query string and turn it .toUpperCase()
.
As pointed by Polygenelubricants, you need to pass concrete runtime types around, e.g. Class<?>
instead of syntactic compiletime types like generic parameters. Here's a rewrite how you could use it:
public abstract class CommonEnumTypeHandler<E extends Enum<E>> implements TypeHandlerCallback {
private Class<E> enumClass;
public CommonEnumTypeHandler(Class<E> enumClass) {
this.enumClass = enumClass;
}
public void setParameter(ParameterSetter ps, Object o) throws SQLException {
if (enumClass.isInstance(o)) {
ps.setString((enumClass.cast(o)).name().toUpperCase());
} else {
throw new SQLException("Excpected ParameterType object than: " + o);
}
}
public Object getResult(ResultGetter rs) throws SQLException {
try {
return Enum.valueOf(enumClass, rs.getString());
} catch (IllegalArgumentException e) {
throw new SQLException("Unknown parameter type: " + rs.getString(), e);
}
}
}
Which you can then use as follows:
public class XEnumTypeHandler extends CommonEnumTypeHandler<X> {
public XEnumTypeHandler() {
super(X.class);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With