Parametrized class issue - java

I´m getting a weird behaviour with parametrized types.
I´ve a class A that extends the class B. A has an inner class A1 that extends the class Predicate.
The code looks like this:
public abstract class A<T> extends B<T> {
public T uniqueResult (String param, Object value) {
A1 filter = new A1();
filter.setParam(param);
filter.setValue(value);
return container.query(filter).next();
}
public class A1 extends Predicate<T> {
public boolean match (T bean) {
Object result = BeanUtils.getPropertyValue(bean, fieldName);
return result == null ? null : result.equals(value);
}
}
}
Finally the class D extends A and uses the uniqueResult method:
public class D extends A<MyVO> {
public MyVO findById (BigDecimal id) {
return uniqueResult("id", id);
}
}
The problem is that the match method (inside A1) receives BigDecimal instead of MyVO.
If I override the uniqueResult method in D it works fine but I don´t get why this happens.
The overrided uniqueResult looks like this:
public MyVO uniqueResult (final String fieldName, final Object value) {
return container().query(
new Predicate<MyVO>() {
private static final long serialVersionUID = 1L;
public boolean match(MyVO bean) {
Object result = BeanUtils.getPropertyValue(bean, fieldName);
return result == null ? null : result.equals(value);
}
}
).next();
}
Any idea?

Behavior can't be affected by generics at all. It's compile-time feature and the generics info is (effectively) lost after compilation. So the problem is somewhere else, IMO.
Btw why don't you introduce just Predicate getFilter() and override override just that. Would get more readable.

The problem was at Java Generics type erasure.
The API I am using (that contains the class Predicate) has an issue when creating a predicate parametrized like Predicate. Fortunately, it provides a constructor that receives the concrete class to be matched as argument. It isn´t elegant but it works.
The code is like this:
The method uniqueResult in A:
protected T uniqueResult (final String fieldName, final Object value) {
return container().query(
new Predicate<T>(getPredicateClass()) {
private static final long serialVersionUID = 1L;
public boolean match(T bean) {
Object result = BeanUtils.getPropertyValue(bean, fieldName);
return result == null ? null : result.equals(value);
}
}
).next();
}
Added
protected abstract Class<T> getPredicateClass();
Finally in D:
protected Class<MyVO> getPredicateClass() {
return MyVO.class;
}
Regards!

Related

Write a single generics method to cover multiple methods for String to Enum value conversion

I created two Java enums,
public enum TypeEnum {
TYPE_A, TYPE_B
}
and
public enum FormatEnum{
FORMAT_X, FORMAT_Y
}
Next, I wrote two functions to convert an incoming String to an enum value:
private TypeEnum convertType(String test) {
return TypeEnum.valueOf(test);
}
private FormatEnum convertFormat(String test) {
return FormatEnum.valueOf(test);
}
Next, I wanted to unify these two conversion methods under a single method with generics. I tried this in two ways:
private <T extends Enum> Enum convertToEnumValue(T localEnum, String value) {
return T.valueOf(localEnum.getClass(), value);
}
and
private static <T extends Enum> T convertToEnumValue(Class<T> enumType, String value) {
return (T) T.valueOf(enumType, value);
}
I couldn't write a call to these methods that would compile.
Is there a way to correct them to make them work?
There is no need to declare your own method, as JDK java.lang.Enum already declares one:
FormatEnum y =Enum.valueOf(FormatEnum.class, "FORMAT_Y");
TypeEnum a = Enum.valueOf(TypeEnum.class, "TYPE_A");
This works because Enum is the base class of all enum types and so when you call TypeEnum.valueOf(s); you are calling Enum.valueOf(s)
…Is there a way to correct them to make them work?…
I got your examples to work with these very small corrections…:
class DeduperAnswer {
private <T extends Enum> T convertToEnumValue(T localEnum, String value) {
return ( T ) T.valueOf(localEnum.getClass(), value);
}
private static <T extends Enum> T convertToEnumValue(Class<T> enumType, String value) {
return ( T ) T.valueOf(enumType, value);
}
static public void main(String ...args){
DeduperAnswer da = new DeduperAnswer();
TypeEnum typB = da.convertToEnumValue(TypeEnum.TYPE_B, "TYPE_B");
FormatEnum fmtX = convertToEnumValue(FormatEnum.FORMAT_X.getClass(), "FORMAT_X");
}
}
Of course, there's more than one way to skin a cat — as the saying goes. But seeing as your solution works for you, you're good to go.
I suspect you are looking for the following method:
public static <E extends Enum<E>> E toMember(Class<E> clazz, String name) {
//TODO input validations;
for (E member : clazz.getEnumConstants()) {
if (member.name().equals(name)) {
return member;
}
}
return null; //Or throw element not found exception
}
//More elegant form of the previous one
public static <E extends Enum<E>> E toMember(Class<E> clazz, String name, E defaultMember) {
//TODO input validations;
for (E member : clazz.getEnumConstants()) {
if (member.name().equals(name)) {
return member;
}
}
return defaultMember;
}
Note the generic E extends Enum<E>

Java: How to get the class type of generics at runtime? [duplicate]

How can I achieve this?
public class GenericClass<T>
{
public Type getMyType()
{
//How do I return the type of T?
}
}
Everything I have tried so far always returns type Object rather than the specific type used.
As others mentioned, it's only possible via reflection in certain circumstances.
If you really need the type, this is the usual (type-safe) workaround pattern:
public class GenericClass<T> {
private final Class<T> type;
public GenericClass(Class<T> type) {
this.type = type;
}
public Class<T> getMyType() {
return this.type;
}
}
I have seen something like this
private Class<T> persistentClass;
public Constructor() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
in the hibernate GenericDataAccessObjects Example
Generics are not reified at run-time. This means the information is not present at run-time.
Adding generics to Java while mantaining backward compatibility was a tour-de-force (you can see the seminal paper about it: Making the future safe for the past: adding genericity to the Java programming language).
There is a rich literature on the subject, and some people are dissatisfied with the current state, some says that actually it's a lure and there is no real need for it. You can read both links, I found them quite interesting.
Use Guava.
import com.google.common.reflect.TypeToken;
import java.lang.reflect.Type;
public abstract class GenericClass<T> {
private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) { };
private final Type type = typeToken.getType(); // or getRawType() to return Class<? super T>
public Type getType() {
return type;
}
public static void main(String[] args) {
GenericClass<String> example = new GenericClass<String>() { };
System.out.println(example.getType()); // => class java.lang.String
}
}
A while back, I posted some full-fledge examples including abstract classes and subclasses here.
Note: this requires that you instantiate a subclass of GenericClass so it can bind the type parameter correctly. Otherwise it'll just return the type as T.
Java generics are mostly compile time, this means that the type information is lost at runtime.
class GenericCls<T>
{
T t;
}
will be compiled to something like
class GenericCls
{
Object o;
}
To get the type information at runtime you have to add it as an argument of the ctor.
class GenericCls<T>
{
private Class<T> type;
public GenericCls(Class<T> cls)
{
type= cls;
}
Class<T> getType(){return type;}
}
Example:
GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;
Sure, you can.
Java does not use the information at run time, for backwards compatibility reasons. But the information is actually present as metadata and can be accessed via reflection (but it is still not used for type-checking).
From the official API:
http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29
However, for your scenario I would not use reflection. I'm personally more inclined to use that for framework code. In your case I would just add the type as a constructor param.
public abstract class AbstractDao<T>
{
private final Class<T> persistentClass;
public AbstractDao()
{
this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
}
I used follow approach:
public class A<T> {
protected Class<T> clazz;
public A() {
this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public Class<T> getClazz() {
return clazz;
}
}
public class B extends A<C> {
/* ... */
public void anything() {
// here I may use getClazz();
}
}
I dont think you can, Java uses type erasure when compiling so your code is compatible with applications and libraries that were created pre-generics.
From the Oracle Docs:
Type Erasure
Generics were introduced to the Java language to provide tighter type
checks at compile time and to support generic programming. To
implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or
Object if the type parameters are unbounded. The produced bytecode,
therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety. Generate
bridge methods to preserve polymorphism in extended generic types.
Type erasure ensures that no new classes are created for parameterized
types; consequently, generics incur no runtime overhead.
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
Technique described in this article by Ian Robertson works for me.
In short quick and dirty example:
public abstract class AbstractDAO<T extends EntityInterface, U extends QueryCriteria, V>
{
/**
* Method returns class implementing EntityInterface which was used in class
* extending AbstractDAO
*
* #return Class<T extends EntityInterface>
*/
public Class<T> returnedClass()
{
return (Class<T>) getTypeArguments(AbstractDAO.class, getClass()).get(0);
}
/**
* Get the underlying class for a type, or null if the type is a variable
* type.
*
* #param type the type
* #return the underlying class
*/
public static Class<?> getClass(Type type)
{
if (type instanceof Class) {
return (Class) type;
} else if (type instanceof ParameterizedType) {
return getClass(((ParameterizedType) type).getRawType());
} else if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
Class<?> componentClass = getClass(componentType);
if (componentClass != null) {
return Array.newInstance(componentClass, 0).getClass();
} else {
return null;
}
} else {
return null;
}
}
/**
* Get the actual type arguments a child class has used to extend a generic
* base class.
*
* #param baseClass the base class
* #param childClass the child class
* #return a list of the raw classes for the actual type arguments.
*/
public static <T> List<Class<?>> getTypeArguments(
Class<T> baseClass, Class<? extends T> childClass)
{
Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
Type type = childClass;
// start walking up the inheritance hierarchy until we hit baseClass
while (!getClass(type).equals(baseClass)) {
if (type instanceof Class) {
// there is no useful information for us in raw types, so just keep going.
type = ((Class) type).getGenericSuperclass();
} else {
ParameterizedType parameterizedType = (ParameterizedType) type;
Class<?> rawType = (Class) parameterizedType.getRawType();
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
for (int i = 0; i < actualTypeArguments.length; i++) {
resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
}
if (!rawType.equals(baseClass)) {
type = rawType.getGenericSuperclass();
}
}
}
// finally, for each actual type argument provided to baseClass, determine (if possible)
// the raw class for that type argument.
Type[] actualTypeArguments;
if (type instanceof Class) {
actualTypeArguments = ((Class) type).getTypeParameters();
} else {
actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
}
List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
// resolve types by chasing down type variables.
for (Type baseType : actualTypeArguments) {
while (resolvedTypes.containsKey(baseType)) {
baseType = resolvedTypes.get(baseType);
}
typeArgumentsAsClasses.add(getClass(baseType));
}
return typeArgumentsAsClasses;
}
}
I think there is another elegant solution.
What you want to do is (safely) "pass" the type of the generic type parameter up from the concerete class to the superclass.
If you allow yourself to think of the class type as "metadata" on the class, that suggests the Java method for encoding metadata in at runtime: annotations.
First define a custom annotation along these lines:
import java.lang.annotation.*;
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface EntityAnnotation {
Class entityClass();
}
You can then have to add the annotation to your subclass.
#EntityAnnotation(entityClass = PassedGenericType.class)
public class Subclass<PassedGenericType> {...}
Then you can use this code to get the class type in your base class:
import org.springframework.core.annotation.AnnotationUtils;
.
.
.
private Class getGenericParameterType() {
final Class aClass = this.getClass();
EntityAnnotation ne =
AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class);
return ne.entityClass();
}
Some limitations of this approach are:
You specify the generic type (PassedGenericType) in TWO places rather than one which is non-DRY.
This is only possible if you can modify the concrete subclasses.
Here's one way, which I've had to use once or twice:
public abstract class GenericClass<T>{
public abstract Class<T> getMyType();
}
Along with
public class SpecificClass extends GenericClass<String>{
#Override
public Class<String> getMyType(){
return String.class;
}
}
This is my solution:
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
public class GenericClass<T extends String> {
public static void main(String[] args) {
for (TypeVariable typeParam : GenericClass.class.getTypeParameters()) {
System.out.println(typeParam.getName());
for (Type bound : typeParam.getBounds()) {
System.out.println(bound);
}
}
}
}
Here is working solution!!!
#SuppressWarnings("unchecked")
private Class<T> getGenericTypeClass() {
    try {
        String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
        Class<?> clazz = Class.forName(className);
        return (Class<T>) clazz;
    } catch (Exception e) {
        throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
    }
}
NOTES:
Can be used only as superclass
1. Has to be extended with typed class (Child extends Generic<Integer>)
OR
2. Has to be created as anonymous implementation (new Generic<Integer>() {};)
You can't. If you add a member variable of type T to the class (you don't even have to initialise it), you could use that to recover the type.
One simple solution for this cab be like below
public class GenericDemo<T>{
private T type;
GenericDemo(T t)
{
this.type = t;
}
public String getType()
{
return this.type.getClass().getName();
}
public static void main(String[] args)
{
GenericDemo<Integer> obj = new GenericDemo<Integer>(5);
System.out.println("Type: "+ obj.getType());
}
}
To complete some of the answers here, I had to get the ParametrizedType of MyGenericClass, no matter how high is the hierarchy, with the help of recursion:
private Class<T> getGenericTypeClass() {
return (Class<T>) (getParametrizedType(getClass())).getActualTypeArguments()[0];
}
private static ParameterizedType getParametrizedType(Class clazz){
if(clazz.getSuperclass().equals(MyGenericClass.class)){ // check that we are at the top of the hierarchy
return (ParameterizedType) clazz.getGenericSuperclass();
} else {
return getParametrizedType(clazz.getSuperclass());
}
}
Here is my solution
public class GenericClass<T>
{
private Class<T> realType;
public GenericClass() {
findTypeArguments(getClass());
}
private void findTypeArguments(Type t) {
if (t instanceof ParameterizedType) {
Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments();
realType = (Class<T>) typeArgs[0];
} else {
Class c = (Class) t;
findTypeArguments(c.getGenericSuperclass());
}
}
public Type getMyType()
{
// How do I return the type of T? (your question)
return realType;
}
}
No matter how many level does your class hierarchy has,
this solution still works, for example:
public class FirstLevelChild<T> extends GenericClass<T> {
}
public class SecondLevelChild extends FirstLevelChild<String> {
}
In this case, getMyType() = java.lang.String
Here is my trick:
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(Main.<String> getClazz());
}
static <T> Class getClazz(T... param) {
return param.getClass().getComponentType();
}
}
Just in case you use store a variable using the generic type you can easily solve this problem adding a getClassType method as follows:
public class Constant<T> {
private T value;
#SuppressWarnings("unchecked")
public Class<T> getClassType () {
return ((Class<T>) value.getClass());
}
}
I use the provided class object later to check if it is an instance of a given class, as follows:
Constant<?> constant = ...;
if (constant.getClassType().equals(Integer.class)) {
Constant<Integer> integerConstant = (Constant<Integer>)constant;
Integer value = integerConstant.getValue();
// ...
}
Here is my solution. The examples should explain it. The only requirement is that a subclass must set the generic type, not an object.
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;
public class TypeUtils {
/*** EXAMPLES ***/
public static class Class1<A, B, C> {
public A someA;
public B someB;
public C someC;
public Class<?> getAType() {
return getTypeParameterType(this.getClass(), Class1.class, 0);
}
public Class<?> getCType() {
return getTypeParameterType(this.getClass(), Class1.class, 2);
}
}
public static class Class2<D, A, B, E, C> extends Class1<A, B, C> {
public B someB;
public D someD;
public E someE;
}
public static class Class3<E, C> extends Class2<String, Integer, Double, E, C> {
public E someE;
}
public static class Class4 extends Class3<Boolean, Long> {
}
public static void test() throws NoSuchFieldException {
Class4 class4 = new Class4();
Class<?> typeA = class4.getAType(); // typeA = Integer
Class<?> typeC = class4.getCType(); // typeC = Long
Field fieldSomeA = class4.getClass().getField("someA");
Class<?> typeSomeA = TypeUtils.getFieldType(class4.getClass(), fieldSomeA); // typeSomeA = Integer
Field fieldSomeE = class4.getClass().getField("someE");
Class<?> typeSomeE = TypeUtils.getFieldType(class4.getClass(), fieldSomeE); // typeSomeE = Boolean
}
/*** UTILS ***/
public static Class<?> getTypeVariableType(Class<?> subClass, TypeVariable<?> typeVariable) {
Map<TypeVariable<?>, Type> subMap = new HashMap<>();
Class<?> superClass;
while ((superClass = subClass.getSuperclass()) != null) {
Map<TypeVariable<?>, Type> superMap = new HashMap<>();
Type superGeneric = subClass.getGenericSuperclass();
if (superGeneric instanceof ParameterizedType) {
TypeVariable<?>[] typeParams = superClass.getTypeParameters();
Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments();
for (int i = 0; i < typeParams.length; i++) {
Type actualType = actualTypeArgs[i];
if (actualType instanceof TypeVariable) {
actualType = subMap.get(actualType);
}
if (typeVariable == typeParams[i]) return (Class<?>) actualType;
superMap.put(typeParams[i], actualType);
}
}
subClass = superClass;
subMap = superMap;
}
return null;
}
public static Class<?> getTypeParameterType(Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
return TypeUtils.getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex]);
}
public static Class<?> getFieldType(Class<?> clazz, AccessibleObject element) {
Class<?> type = null;
Type genericType = null;
if (element instanceof Field) {
type = ((Field) element).getType();
genericType = ((Field) element).getGenericType();
} else if (element instanceof Method) {
type = ((Method) element).getReturnType();
genericType = ((Method) element).getGenericReturnType();
}
if (genericType instanceof TypeVariable) {
Class<?> typeVariableType = TypeUtils.getTypeVariableType(clazz, (TypeVariable) genericType);
if (typeVariableType != null) {
type = typeVariableType;
}
}
return type;
}
}
If you have a class like:
public class GenericClass<T> {
private T data;
}
with T variable, then you can print T name:
System.out.println(data.getClass().getSimpleName()); // "String", "Integer", etc.
Use an abstract method that returns the class type then use it in that class and wherever you extend generic class you will have to implement that abstract method to return the required class type
public class AbsractService<T>{
public abstract Class<T> getClassType ();
.......
}
at runtime
class AnimalService extends AbstractService<Animal>{
#Override
public Class<Animal> getClassType (){
return Animal.class;
}
.....
}
public static final Class<?> getGenericArgument(final Class<?> clazz)
{
return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
}
If you are working with spring:
public static Class<?>[] resolveTypeArguments(Class<?> parentClass, Class<?> subClass) {
if (subClass.isSynthetic()) {
return null;
}
return GenericTypeResolver.resolveTypeArguments(subClass, parentClass);
}
By the way, GenericTypeResolver will still get null for the non-subclasses class like the question mentioned, because the generic info of such class was completely erased after compilation.
The only way to solve this question may be:
public class GenericClass<T>
{
private final Class<T> clazz;
public Foo(Class<T> clazz) {
this.clazz= clazz;
}
public Type getMyType()
{
return clazz;
}
}
If you cannot change the generic class and use one of the method already explained on this page, then simple approach would be to get the type class based on the runtime instance class name.
Class getType(GenericType runtimeClassMember){
if (ClassA.class.equals(runtimeClassMember.getClass()){
return TypeForClassA.class;
} else if (ClassB.class.equals(runtimeClassMember.getClass()){
return TypeForClassB.class;
}
//throw an expectation or do whatever you want for the cases not described in the if section.
}
I did the same as #Moesio Above but in Kotlin it could be done this way:
class A<T : SomeClass>() {
var someClassType : T
init(){
this.someClassType = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>
}
}
This was inspired by Pablo's and CoolMind's answers.
Occasionally I have also used the technique from kayz1's answer (expressed in many other answers as well), and I believe it is a decent and reliable way to do what the OP asked.
I chose to define this as an interface (similar to PJWeisberg) first because I have existing types that would benefit from this functionality, particularly a heterogeneous generic union type:
public interface IGenericType<T>
{
Class<T> getGenericTypeParameterType();
}
Where my simple implementation in a generic anonymous interface implementation looks like the following:
//Passed into the generic value generator function: toStore
//This value name is a field in the enclosing class.
//IUnionTypeValue<T> is a generic interface that extends IGenericType<T>
value = new IUnionTypeValue<T>() {
...
private T storedValue = toStore;
...
#SuppressWarnings("unchecked")
#Override
public Class<T> getGenericTypeParameterType()
{
return (Class<T>) storedValue.getClass();
}
}
I imagine this could be also implemented by being built with a class definition object as the source, that's just a separate use-case.
I think the key is as many other answers have stated, in one way or another, you need to get the type information at runtime to have it available at runtime; the objects themselves maintain their type, but erasure (also as others have said, with appropriate references) causes any enclosing/container types to lose that type information.
It might be useful to someone. You can Use java.lang.ref.WeakReference;
this way:
class SomeClass<N>{
WeakReference<N> variableToGetTypeFrom;
N getType(){
return variableToGetTypeFrom.get();
}
}
I found this to be a simple understandable and easily explainable solution
public class GenericClass<T> {
private Class classForT(T...t) {
return t.getClass().getComponentType();
}
public static void main(String[] args) {
GenericClass<String> g = new GenericClass<String>();
System.out.println(g.classForT());
System.out.println(String.class);
}
}

Why this converter needs casting?

I need to implement an enum to enum converter in java: Enum_2 > Enum_1 and I'd like to do it in generic way.
So I defined an interface:
interface LabelAware<T extends Enum> {
String getLabel();
T getObject();
}
and Enum_1:
enum Enum_1 {
A, B;
String getValue() {
return "whatever";
}
}
and Enum_2 which implements LabelAware and needs to be converted to Enum_1:
enum Enum_2 implements LabelAware<Enum_1> {
C("c", Enum_1.A), D("d", Enum_1.B);
private final String label;
private final Enum_1 object;
Enum_2(String label, Enum_1 object) {
this.label = label;
this.object = object;
}
public String getLabel() {
return label;
}
public Enum_1 getObject() {
return object;
}
}
Finally, here's a generic converter (List.ofAll() comes from javaslang):
class Converter<S extends LabelAware, D extends Enum> {
private S[] values;
Converter(S[] values) {
this.values = values;
}
D map(String label) {
return (D) List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
}
And a main method:
public class Main {
public static void main(String[] args) {
System.out.println(new Converter<Enum_2, Enum_1>(Enum_2.values()).map("c").getValue());
}
}
It all compiles and runs well, however I've no idea why I need to cast the result of Converter.map method to D, since I've declared D to extend Enum. Can it be done in a generic way without any warnings?
As a general rule, all warnings related to generics should be handled to have a safer code and avoid a warning chain (the visible warning is caused by a very far warning of the dependency chain).
But in your case, you have not a warning chain problem since externally, LabelAware is safe. LabelAware has only a internal warning (in its implementation) as Enum in extends Enum is raw-declared.
Here, a single missing generic declaration explains why the cast in Converter.map() method is not safe : Converter class declaration doesn't specify the generic for LabelAware.
You declare Converter class as :
class Converter<S extends LabelAware, D extends Enum> {
with its value field of type S:
private S[] values;
and its map() method as :
D map(String label) {
return (D) List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
In map(), here .find(v -> v.getLabel().equals(label)), your retrieve so a S instance and you declared that S extends LabelAware.
Therefore finally, your retrieve an instance of LabelAware or extending it.
And LabelAware is typed with Enum generic :
interface LabelAware<T extends Enum> {
String getLabel();
T getObject();
}
So, in map() method when .map(LabelAware::getObject) is called, you retrieve a Enum type .
And an Enum type is not necessarily a D type, while the reverse is true.
Therefore, if you want to avoid the cast (and the related warning) in map(), you should specify that the generic type returned by getObject() is an instance of D by typing LabelAware with D generic :
class Converter<S extends LabelAware<D>, D extends Enum> {
You have been using raw types at several places (not only the one that yshavit pointed out in the comment). Particularly, the
class Converter<S extends LabelAware, D extends Enum>
has to be
class Converter<S extends LabelAware<D>, D extends Enum<D>>
The following should compile without warnings:
import javaslang.collection.List;
interface LabelAware<T extends Enum<?>>
{
String getLabel();
T getObject();
}
enum Enum_1
{
A, B;
String getValue()
{
return "whatever";
}
}
enum Enum_2 implements LabelAware<Enum_1>
{
C("c", Enum_1.A), D("d", Enum_1.B);
private final String label;
private final Enum_1 object;
Enum_2(String label, Enum_1 object)
{
this.label = label;
this.object = object;
}
public String getLabel()
{
return label;
}
public Enum_1 getObject()
{
return object;
}
}
class Converter<S extends LabelAware<D>, D extends Enum<D>>
{
private S[] values;
Converter(S[] values)
{
this.values = values;
}
D map(String label)
{
return List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
}
(EDIT: This only tells you how to fix the problem, pragmatically. See the answer by davidxxx for details about what went wrong there, and don't forget to leave a +1 there :-))

Get generic type information [duplicate]

How can I achieve this?
public class GenericClass<T>
{
public Type getMyType()
{
//How do I return the type of T?
}
}
Everything I have tried so far always returns type Object rather than the specific type used.
As others mentioned, it's only possible via reflection in certain circumstances.
If you really need the type, this is the usual (type-safe) workaround pattern:
public class GenericClass<T> {
private final Class<T> type;
public GenericClass(Class<T> type) {
this.type = type;
}
public Class<T> getMyType() {
return this.type;
}
}
I have seen something like this
private Class<T> persistentClass;
public Constructor() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
in the hibernate GenericDataAccessObjects Example
Generics are not reified at run-time. This means the information is not present at run-time.
Adding generics to Java while mantaining backward compatibility was a tour-de-force (you can see the seminal paper about it: Making the future safe for the past: adding genericity to the Java programming language).
There is a rich literature on the subject, and some people are dissatisfied with the current state, some says that actually it's a lure and there is no real need for it. You can read both links, I found them quite interesting.
Use Guava.
import com.google.common.reflect.TypeToken;
import java.lang.reflect.Type;
public abstract class GenericClass<T> {
private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) { };
private final Type type = typeToken.getType(); // or getRawType() to return Class<? super T>
public Type getType() {
return type;
}
public static void main(String[] args) {
GenericClass<String> example = new GenericClass<String>() { };
System.out.println(example.getType()); // => class java.lang.String
}
}
A while back, I posted some full-fledge examples including abstract classes and subclasses here.
Note: this requires that you instantiate a subclass of GenericClass so it can bind the type parameter correctly. Otherwise it'll just return the type as T.
Java generics are mostly compile time, this means that the type information is lost at runtime.
class GenericCls<T>
{
T t;
}
will be compiled to something like
class GenericCls
{
Object o;
}
To get the type information at runtime you have to add it as an argument of the ctor.
class GenericCls<T>
{
private Class<T> type;
public GenericCls(Class<T> cls)
{
type= cls;
}
Class<T> getType(){return type;}
}
Example:
GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;
Sure, you can.
Java does not use the information at run time, for backwards compatibility reasons. But the information is actually present as metadata and can be accessed via reflection (but it is still not used for type-checking).
From the official API:
http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29
However, for your scenario I would not use reflection. I'm personally more inclined to use that for framework code. In your case I would just add the type as a constructor param.
public abstract class AbstractDao<T>
{
private final Class<T> persistentClass;
public AbstractDao()
{
this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
}
I used follow approach:
public class A<T> {
protected Class<T> clazz;
public A() {
this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public Class<T> getClazz() {
return clazz;
}
}
public class B extends A<C> {
/* ... */
public void anything() {
// here I may use getClazz();
}
}
I dont think you can, Java uses type erasure when compiling so your code is compatible with applications and libraries that were created pre-generics.
From the Oracle Docs:
Type Erasure
Generics were introduced to the Java language to provide tighter type
checks at compile time and to support generic programming. To
implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or
Object if the type parameters are unbounded. The produced bytecode,
therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety. Generate
bridge methods to preserve polymorphism in extended generic types.
Type erasure ensures that no new classes are created for parameterized
types; consequently, generics incur no runtime overhead.
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
Technique described in this article by Ian Robertson works for me.
In short quick and dirty example:
public abstract class AbstractDAO<T extends EntityInterface, U extends QueryCriteria, V>
{
/**
* Method returns class implementing EntityInterface which was used in class
* extending AbstractDAO
*
* #return Class<T extends EntityInterface>
*/
public Class<T> returnedClass()
{
return (Class<T>) getTypeArguments(AbstractDAO.class, getClass()).get(0);
}
/**
* Get the underlying class for a type, or null if the type is a variable
* type.
*
* #param type the type
* #return the underlying class
*/
public static Class<?> getClass(Type type)
{
if (type instanceof Class) {
return (Class) type;
} else if (type instanceof ParameterizedType) {
return getClass(((ParameterizedType) type).getRawType());
} else if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
Class<?> componentClass = getClass(componentType);
if (componentClass != null) {
return Array.newInstance(componentClass, 0).getClass();
} else {
return null;
}
} else {
return null;
}
}
/**
* Get the actual type arguments a child class has used to extend a generic
* base class.
*
* #param baseClass the base class
* #param childClass the child class
* #return a list of the raw classes for the actual type arguments.
*/
public static <T> List<Class<?>> getTypeArguments(
Class<T> baseClass, Class<? extends T> childClass)
{
Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
Type type = childClass;
// start walking up the inheritance hierarchy until we hit baseClass
while (!getClass(type).equals(baseClass)) {
if (type instanceof Class) {
// there is no useful information for us in raw types, so just keep going.
type = ((Class) type).getGenericSuperclass();
} else {
ParameterizedType parameterizedType = (ParameterizedType) type;
Class<?> rawType = (Class) parameterizedType.getRawType();
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
for (int i = 0; i < actualTypeArguments.length; i++) {
resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
}
if (!rawType.equals(baseClass)) {
type = rawType.getGenericSuperclass();
}
}
}
// finally, for each actual type argument provided to baseClass, determine (if possible)
// the raw class for that type argument.
Type[] actualTypeArguments;
if (type instanceof Class) {
actualTypeArguments = ((Class) type).getTypeParameters();
} else {
actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
}
List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
// resolve types by chasing down type variables.
for (Type baseType : actualTypeArguments) {
while (resolvedTypes.containsKey(baseType)) {
baseType = resolvedTypes.get(baseType);
}
typeArgumentsAsClasses.add(getClass(baseType));
}
return typeArgumentsAsClasses;
}
}
I think there is another elegant solution.
What you want to do is (safely) "pass" the type of the generic type parameter up from the concerete class to the superclass.
If you allow yourself to think of the class type as "metadata" on the class, that suggests the Java method for encoding metadata in at runtime: annotations.
First define a custom annotation along these lines:
import java.lang.annotation.*;
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface EntityAnnotation {
Class entityClass();
}
You can then have to add the annotation to your subclass.
#EntityAnnotation(entityClass = PassedGenericType.class)
public class Subclass<PassedGenericType> {...}
Then you can use this code to get the class type in your base class:
import org.springframework.core.annotation.AnnotationUtils;
.
.
.
private Class getGenericParameterType() {
final Class aClass = this.getClass();
EntityAnnotation ne =
AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class);
return ne.entityClass();
}
Some limitations of this approach are:
You specify the generic type (PassedGenericType) in TWO places rather than one which is non-DRY.
This is only possible if you can modify the concrete subclasses.
Here's one way, which I've had to use once or twice:
public abstract class GenericClass<T>{
public abstract Class<T> getMyType();
}
Along with
public class SpecificClass extends GenericClass<String>{
#Override
public Class<String> getMyType(){
return String.class;
}
}
This is my solution:
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
public class GenericClass<T extends String> {
public static void main(String[] args) {
for (TypeVariable typeParam : GenericClass.class.getTypeParameters()) {
System.out.println(typeParam.getName());
for (Type bound : typeParam.getBounds()) {
System.out.println(bound);
}
}
}
}
Here is working solution!!!
#SuppressWarnings("unchecked")
private Class<T> getGenericTypeClass() {
    try {
        String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
        Class<?> clazz = Class.forName(className);
        return (Class<T>) clazz;
    } catch (Exception e) {
        throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
    }
}
NOTES:
Can be used only as superclass
1. Has to be extended with typed class (Child extends Generic<Integer>)
OR
2. Has to be created as anonymous implementation (new Generic<Integer>() {};)
You can't. If you add a member variable of type T to the class (you don't even have to initialise it), you could use that to recover the type.
One simple solution for this cab be like below
public class GenericDemo<T>{
private T type;
GenericDemo(T t)
{
this.type = t;
}
public String getType()
{
return this.type.getClass().getName();
}
public static void main(String[] args)
{
GenericDemo<Integer> obj = new GenericDemo<Integer>(5);
System.out.println("Type: "+ obj.getType());
}
}
To complete some of the answers here, I had to get the ParametrizedType of MyGenericClass, no matter how high is the hierarchy, with the help of recursion:
private Class<T> getGenericTypeClass() {
return (Class<T>) (getParametrizedType(getClass())).getActualTypeArguments()[0];
}
private static ParameterizedType getParametrizedType(Class clazz){
if(clazz.getSuperclass().equals(MyGenericClass.class)){ // check that we are at the top of the hierarchy
return (ParameterizedType) clazz.getGenericSuperclass();
} else {
return getParametrizedType(clazz.getSuperclass());
}
}
Here is my solution
public class GenericClass<T>
{
private Class<T> realType;
public GenericClass() {
findTypeArguments(getClass());
}
private void findTypeArguments(Type t) {
if (t instanceof ParameterizedType) {
Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments();
realType = (Class<T>) typeArgs[0];
} else {
Class c = (Class) t;
findTypeArguments(c.getGenericSuperclass());
}
}
public Type getMyType()
{
// How do I return the type of T? (your question)
return realType;
}
}
No matter how many level does your class hierarchy has,
this solution still works, for example:
public class FirstLevelChild<T> extends GenericClass<T> {
}
public class SecondLevelChild extends FirstLevelChild<String> {
}
In this case, getMyType() = java.lang.String
Here is my trick:
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(Main.<String> getClazz());
}
static <T> Class getClazz(T... param) {
return param.getClass().getComponentType();
}
}
Just in case you use store a variable using the generic type you can easily solve this problem adding a getClassType method as follows:
public class Constant<T> {
private T value;
#SuppressWarnings("unchecked")
public Class<T> getClassType () {
return ((Class<T>) value.getClass());
}
}
I use the provided class object later to check if it is an instance of a given class, as follows:
Constant<?> constant = ...;
if (constant.getClassType().equals(Integer.class)) {
Constant<Integer> integerConstant = (Constant<Integer>)constant;
Integer value = integerConstant.getValue();
// ...
}
Here is my solution. The examples should explain it. The only requirement is that a subclass must set the generic type, not an object.
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;
public class TypeUtils {
/*** EXAMPLES ***/
public static class Class1<A, B, C> {
public A someA;
public B someB;
public C someC;
public Class<?> getAType() {
return getTypeParameterType(this.getClass(), Class1.class, 0);
}
public Class<?> getCType() {
return getTypeParameterType(this.getClass(), Class1.class, 2);
}
}
public static class Class2<D, A, B, E, C> extends Class1<A, B, C> {
public B someB;
public D someD;
public E someE;
}
public static class Class3<E, C> extends Class2<String, Integer, Double, E, C> {
public E someE;
}
public static class Class4 extends Class3<Boolean, Long> {
}
public static void test() throws NoSuchFieldException {
Class4 class4 = new Class4();
Class<?> typeA = class4.getAType(); // typeA = Integer
Class<?> typeC = class4.getCType(); // typeC = Long
Field fieldSomeA = class4.getClass().getField("someA");
Class<?> typeSomeA = TypeUtils.getFieldType(class4.getClass(), fieldSomeA); // typeSomeA = Integer
Field fieldSomeE = class4.getClass().getField("someE");
Class<?> typeSomeE = TypeUtils.getFieldType(class4.getClass(), fieldSomeE); // typeSomeE = Boolean
}
/*** UTILS ***/
public static Class<?> getTypeVariableType(Class<?> subClass, TypeVariable<?> typeVariable) {
Map<TypeVariable<?>, Type> subMap = new HashMap<>();
Class<?> superClass;
while ((superClass = subClass.getSuperclass()) != null) {
Map<TypeVariable<?>, Type> superMap = new HashMap<>();
Type superGeneric = subClass.getGenericSuperclass();
if (superGeneric instanceof ParameterizedType) {
TypeVariable<?>[] typeParams = superClass.getTypeParameters();
Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments();
for (int i = 0; i < typeParams.length; i++) {
Type actualType = actualTypeArgs[i];
if (actualType instanceof TypeVariable) {
actualType = subMap.get(actualType);
}
if (typeVariable == typeParams[i]) return (Class<?>) actualType;
superMap.put(typeParams[i], actualType);
}
}
subClass = superClass;
subMap = superMap;
}
return null;
}
public static Class<?> getTypeParameterType(Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
return TypeUtils.getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex]);
}
public static Class<?> getFieldType(Class<?> clazz, AccessibleObject element) {
Class<?> type = null;
Type genericType = null;
if (element instanceof Field) {
type = ((Field) element).getType();
genericType = ((Field) element).getGenericType();
} else if (element instanceof Method) {
type = ((Method) element).getReturnType();
genericType = ((Method) element).getGenericReturnType();
}
if (genericType instanceof TypeVariable) {
Class<?> typeVariableType = TypeUtils.getTypeVariableType(clazz, (TypeVariable) genericType);
if (typeVariableType != null) {
type = typeVariableType;
}
}
return type;
}
}
If you have a class like:
public class GenericClass<T> {
private T data;
}
with T variable, then you can print T name:
System.out.println(data.getClass().getSimpleName()); // "String", "Integer", etc.
Use an abstract method that returns the class type then use it in that class and wherever you extend generic class you will have to implement that abstract method to return the required class type
public class AbsractService<T>{
public abstract Class<T> getClassType ();
.......
}
at runtime
class AnimalService extends AbstractService<Animal>{
#Override
public Class<Animal> getClassType (){
return Animal.class;
}
.....
}
public static final Class<?> getGenericArgument(final Class<?> clazz)
{
return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
}
If you are working with spring:
public static Class<?>[] resolveTypeArguments(Class<?> parentClass, Class<?> subClass) {
if (subClass.isSynthetic()) {
return null;
}
return GenericTypeResolver.resolveTypeArguments(subClass, parentClass);
}
By the way, GenericTypeResolver will still get null for the non-subclasses class like the question mentioned, because the generic info of such class was completely erased after compilation.
The only way to solve this question may be:
public class GenericClass<T>
{
private final Class<T> clazz;
public Foo(Class<T> clazz) {
this.clazz= clazz;
}
public Type getMyType()
{
return clazz;
}
}
If you cannot change the generic class and use one of the method already explained on this page, then simple approach would be to get the type class based on the runtime instance class name.
Class getType(GenericType runtimeClassMember){
if (ClassA.class.equals(runtimeClassMember.getClass()){
return TypeForClassA.class;
} else if (ClassB.class.equals(runtimeClassMember.getClass()){
return TypeForClassB.class;
}
//throw an expectation or do whatever you want for the cases not described in the if section.
}
I did the same as #Moesio Above but in Kotlin it could be done this way:
class A<T : SomeClass>() {
var someClassType : T
init(){
this.someClassType = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>
}
}
This was inspired by Pablo's and CoolMind's answers.
Occasionally I have also used the technique from kayz1's answer (expressed in many other answers as well), and I believe it is a decent and reliable way to do what the OP asked.
I chose to define this as an interface (similar to PJWeisberg) first because I have existing types that would benefit from this functionality, particularly a heterogeneous generic union type:
public interface IGenericType<T>
{
Class<T> getGenericTypeParameterType();
}
Where my simple implementation in a generic anonymous interface implementation looks like the following:
//Passed into the generic value generator function: toStore
//This value name is a field in the enclosing class.
//IUnionTypeValue<T> is a generic interface that extends IGenericType<T>
value = new IUnionTypeValue<T>() {
...
private T storedValue = toStore;
...
#SuppressWarnings("unchecked")
#Override
public Class<T> getGenericTypeParameterType()
{
return (Class<T>) storedValue.getClass();
}
}
I imagine this could be also implemented by being built with a class definition object as the source, that's just a separate use-case.
I think the key is as many other answers have stated, in one way or another, you need to get the type information at runtime to have it available at runtime; the objects themselves maintain their type, but erasure (also as others have said, with appropriate references) causes any enclosing/container types to lose that type information.
It might be useful to someone. You can Use java.lang.ref.WeakReference;
this way:
class SomeClass<N>{
WeakReference<N> variableToGetTypeFrom;
N getType(){
return variableToGetTypeFrom.get();
}
}
I found this to be a simple understandable and easily explainable solution
public class GenericClass<T> {
private Class classForT(T...t) {
return t.getClass().getComponentType();
}
public static void main(String[] args) {
GenericClass<String> g = new GenericClass<String>();
System.out.println(g.classForT());
System.out.println(String.class);
}
}

'X.class' to get it's 'X' type?

I have written simple container that registers a class and it's interface and has a method to create object from that information like this:
public class DIContainer {
protected static DIContainer instance;
protected Hashtable<Class<?>, Class<?>> classMap;
protected DIContainer(){
this.classMap = new Hashtable<Class<?>, Class<?>>();
}
public static DIContainer getInstance(){
if (DIContainer.instance == null)
DIContainer.instance = new DIContainer();
return DIContainer.instance;
}
public void regClass(Class<?> interf, Class<?> classToReg){
this.classMap.put(interf, classToReg);
}
public Object create(Class<?> interf) throws Exception{
if(!this.classMap.containsKey(interf))
throw new Exception("No such class registered with "+interf.getName()+" interface");
return this.classMap.get(interf).newInstance();
}
}
But I want before creating new instance to bypass it to proxy, for it to create, so I have this proxy class:
public class MyProxy implements InvocationHandler
{
private Map map;
private Object obj;
public static Object newInstance(Map map, Object obj, Class[] interfaces)
{
return Proxy.newProxyInstance(map.getClass().getClassLoader(),
interfaces,
new MyProxy(map, obj));
}
public MyProxy(Map map, Object obj)
{
this.map = map;
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args) throws
Throwable
{
try {
return m.invoke(obj, args);
} catch (NoSuchMethodError e)
{
//Object result;
String methodName = m.getName();
if (methodName.startsWith("get"))
{
String name = methodName.substring(methodName.indexOf("get")+3);
return map.get(name);
}
else if (methodName.startsWith("set"))
{
String name = methodName.substring(methodName.indexOf("set")+3);
map.put(name, args[0]);
return null;
}
else if (methodName.startsWith("is"))
{
String name = methodName.substring(methodName.indexOf("is")+2);
return(map.get(name));
}
return null;
}
}
}
But for proxy class I need to provide type of class and it's interface, but I only have it's information with X.class. Can get the type (for example if it's class X) X, when I have X.class? Maybe I'm doing this the wrong way and I need to change something in order for it to work, but right now I figured I need to get that class type, so then I could provide it for proxy?
Because if I would right something like this:
X.class x;
I would get error. So I need to write like this X x;, but I only have X.class
Update:
To explain it simply, is it possible to get this:
X obj;
when you only have X.class (with X.class.newInstance it would instantiate it (like with new?), but I need not instantiated obj yet).
Update2
I tried this:
Object x = (Object) MyProxy.newInstance(map, this.classMap.get(interf).newInstance(), new Class[] {this.classMap.get(interf)});
But then I get this error:
Exception in thread "main" java.lang.IllegalArgumentException: class lab.X is not visible from class loader
My class X looks like this:
public class X implements I{
String name;
X(){}
#Override
public String getName() {
return name;
}
#Override
public void setName(String name) {
this.name = name;
}
}
and it's interface looks like this:
public interface I {
public String getName();
public void setName(String name);
}
If I understand correctly, you are trying to instantiate an element of the class X.class? If that is the case, all you need to do is call X.class.newInstance().
java.lang.IllegalArgumentException: class lab.X is not visible from
class loader
Isn't this error message quite clear? You need to make sure that the same class loader is being used.
In here:
public static Object newInstance(Map map, Object obj, Class[] interfaces)
{
return Proxy.newProxyInstance(map.getClass().getClassLoader(),
interfaces,
new MyProxy(map, obj));
}
you shouldn't be using the class loader of the map, I'd think you should use class loader of the target object or pass the proper class loader as a separate argument.
I think there are other problems in your approach as well, such as not synchronizing your container creation and not using generics for your proxy type.
For the first part, class DIContainer, it would be better to use:
protected final Map<Class<?>, Class<?>> classMap;
protected DIContainer() {
classMap = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>());
}
public <I> void regClass(Class<I> interf, Class<? extends I> classToReg) {
this.classMap.put(interf, classToReg);
}
public <T> T create(Class<T> interf) throws Exception {
Class<?> implClass = classMap.get(interf);
if (implClass == null) {
throw new Exception("No such class registered with " + interf.getName()
+ " interface");
}
Constructor<?> c = implClass.getConstructor();
c.setAccessible(true); // If default constructor not public
return interf.cast(c.newInstance());
}
Safe typing, though still partly at run-time.
More or less obsolete Hashtable replaced by equivalent
Calling newInstance on the class bypasses exceptions thrown on getting the default constructor and doing that one's newInstance.
The second part of the question: I fail to understand it; the interface class(es) is what is proxied. In the create above you could easily proxy Class<T> and yield a (seemingly) T object. And you could delegate in the proxy class to an T object created as in the create above.

Categories

Resources