General method for types
I have the following interface:
public interface Caster{
public boolean tryCast(Object value);
}
and its implementation:
public class IntegerCaster{
public boolean tryCast(Object value){
try{
Integer.class.cast(value);
return true;
} catch (ClassCastException e){
return false;
}
}
}
public class DateCaster{
public boolean tryCast(Object value){
try{
Date.class.cast(value);
return true;
} catch (ClassCastException e){
return false;
}
}
}
Can this implementation be generalized? We cannot take and declare Caster with a type parameter because we cannot implement it like this:
public interface Caster<T>{
public boolean tryCast(Object value);
}
public class CasterImpl<T> implements Caster<T>{
public boolean tryCast(Object value){
try{
T.class.cast(value); //fail
return true;
} catch (ClassCastException e){
return false;
}
}
}
source to share
You need to enter the value Class
parameterized T
in your Generic CasterImpl
.
Something like that:
public class CasterImpl<T> implements Caster<T> {
private Clazz<T> clazz;
public CasterImpl(Class<T> clazz) {
this.clazz = clazz;
}
public boolean tryCast(Object value){
try{
clazz.cast(value);
return true;
} catch (ClassCastException e){
return false;
}
}
}
As a side note: I see no reason why the interface Caster
is generic since you are not using the type parameter in the interface.
source to share
This can be done without an interface at all using the standard method Class.isInstance
. If you still want to implement this interface use
public Caster getCaster(final Class<?> clazz) {
return new Caster() {
public boolean tryCast(Object value) {
return clazz.isInstance(value);
}
};
}
Or simpler in Java 8:
public Caster getCaster(final Class<?> clazz) {
return clazz::isInstance;
}
source to share
Generics in Java are implemented by erasure. Java generates one bytecode for everyone T
.
So this:
return T.class.cast(value);
would - if it were allowed - became essentially
return Object.class.cast(value);
no matter which one T
you specify. If you want to test for a specific class, you need an object Class<T>
.
Use instead someclass.isInstance(obj)
.
You are currently inventing the APIClass<T>
.
source to share
Of course, just save the class T
for later use in the constructor:
public interface Caster<T>{
public boolean tryCast(Object value);
}
public class CasterImpl<T> implements Caster<T>{
private Class<? extends T> cls;
public CasterImpl(Class<? extends T> cl) {
this.cls = cl;
}
public boolean tryCast(Object value){
try{
cls.cast(value); //fail
return true;
} catch (ClassCastException e){
return false;
}
}
}
source to share
Generic type instances do not retain their generic type parameter.
You can keep the class as instructed by kocko, or you can store this type of type in a new type this way:
public abstract class CasterImpl<T> implements Caster<T>{
public boolean tryCast(Object value){
try{
getValueClass().cast(value);
return true;
} catch (ClassCastException e){
return false;
}
}
@SuppressWarnings("unchecked")
public Class<T> getValueClass() {
Class<? extends CasterImpl<T>> c = (Class<? extends CasterImpl<T>>) this.getClass();
ParameterizedType x = (ParameterizedType) c.getGenericSuperclass();
return (Class<T>) x.getActualTypeArguments()[0];
}
}
This will only work with subclasses that store the type in their own type definition:
public class CasterIntegerImpl extends CasterImpl<Integer> {
// No need to implement anything
}
Test:
System.out.println(new CasterIntegerImpl().tryCast(1)); // true
System.out.println(new CasterIntegerImpl().tryCast("")); // false
source to share
Try this, use T instead of Object
public interface Caster<T>{
public boolean tryCast(T value);
}
public class CasterImpl<T> implements Caster<T>{
private Class<? extends T> cls;
public CasterImpl(Class<? extends T> cl) {
this.cls = cl;
}
public boolean tryCast(T value){
try{
cls.cast(value); //fail
return true;
} catch (ClassCastException e){
return false;
}
}
source to share