How do I instantiate a new generic class based on class parameters? My main class looks as follows:
public class ServiceTransformer<SERVICE_I, SERVICE_O> extends Loggable {
private Class<SERVICE_I> serviceInputClass;
private Class<SERVICE_O> serviceOutputClass;
public ServiceTransformer(Logger logger, String inputXslt, String outputXslt, String appRoot) {
try {
serviceInputClass = (Class<SERVICE_I>) getGenericTypeClass(0);
serviceOutputClass = (Class<SERVICE_O>) getGenericTypeClass(1);
} catch (BadConfigurationException ex) {
LOGGER.error("@@@ ConfigBase() Constructor Exception => ", ex);
} catch (MalformedURLException ex) {
LOGGER.error("@@@ ConfigBase() Constructor Exception => ", ex);
}
}
private Type getGenericTypeClass(int index) {
try {
return ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[index];
} catch (Exception ex) {
LOGGER.error("@@@ getGenericTypeClass() Exception => ", ex);
}
return null;
}
}
And I instantiate a new ServiceTransformer
class as follows:
ServiceTransformer<ReactivatePrepaidSubscriberInput, ReactivatePrepaidSubcriberOutput> service =
new ServiceTransformer<ReactivatePrepaidSubscriberInput, ReactivatePrepaidSubcriberOutput>(
LOGGER, inputFile, outputFile, APPROOT);
The error that I am currently getting is java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
No idea where I am going wrong.
It is only possible to get the generic type arguments from the superclass, just as you are doing it:
return ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()
But your ServiceTransformer
does not extend a generic class, only Loggable
, which is not generic, hence cannot be cast to ParameterizedType
.
The trick you could do would be to instantiate an anonymous subclass of ServiceTransformer
:
new ServiceTransformer<In, Out>(LOGGER, inputFile, outputFile, APPROOT) {};
(note the {}
at the end)
That would allow access to the generic type arguments of the superclass - this time the superclass is the ServiceTransformer
class itself.
However, note that every time you use this anonymous class construct, a new class is created by the compiler which may affect the performance of your application.
If you are often using a fixed set of <In, Out>
types, create a proper top-level named subclass for it and reuse that, as suggested in other answers. Eg.
class StringIntTransformer extends ServiceTransformer<String, Integer>
if you use the combination often.
The main problem is that generic type arguments can be retrieved only from an inheritance context, you can see it clearly from the method name:
getGenericSuperclass()
This means that you need to instantiate a subtype of ServiceTransformer<I,O>
to be able to query for the type arguments.
This can be done in two ways, you can have a custom real type as
public static class MyServiceTransformer extends ServiceTransformer<ReactivatePrepaidSubscriberInput,ReactivatePrepaidSubcriberOutput>
{
MyServiceTransformer()
{
super(...);
}
}
Or you can define it anonymously:
new ServiceTransformer<ReactivatePrepaidSubscriberInput, ReactivatePrepaidSubcriberOutput>(....){}
First you need a deeper inheritance.
public abstract class AbstractServiceTransformer<SERVICE_I, SERVICE_O> extends Loggable {
private Class<SERVICE_I> serviceInputClass;
private Class<SERVICE_O> serviceOutputClass;
public ServiceTransformer(Logger logger, String inputXslt, String outputXslt, String appRoot) {
serviceInputClass = TypeUtils.getParametrizedType(this.getClass(),0)
serviceOutputClass = TypeUtils.getParametrizedType(this.getClass(),1)
}
...
}
Then here your actual implementation.
public class ServiceTransformer extends AbstractServiceTransformer<Service1, Service2> {
...
}
After that you can read class of type parameters like this.
public final class TypeUtils {
/**
* Returns parameterized type as a Class.
*/
public static <T> Class<T> getParametrizedType(Class<?> baseClass, int index) {
final Type genericSuperClass = baseClass.getGenericSuperclass();
if (!(genericSuperClass instanceof ParameterizedType)) {
throw new IllegalArgumentException("Your super class need to have a parameterized type");
}
final ParameterizedType parameterizedType = (ParameterizedType) genericSuperClass;
final Type[] types = parameterizedType.getActualTypeArguments();
if (types[index] instanceof Class<?>) {
return (Class<T>) types[index];
} else {
throw new IllegalArgumentException("Parameter type is mismatched");
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.