5

I've used Java for quite some time now, but some things are still not very clear to me, especially when it comes to generics...

Here's the thing: I have this Search class that I'm using (see here for details), that is constructed like this:

public Search(Class<?> searchClass) {...}

Further more, I have a parametrized generic wrapper around this, as follows:

public class HibernateSearch<E> extends Search implements Serializable {
    public HibernateSearch(Class<E> entityClass) {
        super(entityClass);
    }
    // ... omitted for brevity
}

Now, what I need is the following: I'd like to create parametrized class, that contains this class as its field, e.g.

public class BaseSelectorComposer<T> extends SelectorComposer<Window> {

    private HibernateSearch<T> searchObject;
    ...
    @Override
    public void doAfterCompose(Window comp) throws Exception {
        super.doAfterCompose(comp);
        this.searchObject =
             new HibernateSearchObject<T>( now what...??? );
        ...
    }
    ...
}

I think that the problem I'm facing is obvious from the given example.
Can someone advise what can be done here, or some alternative ?

Sanne
  • 6,027
  • 19
  • 34
Less
  • 3,047
  • 3
  • 35
  • 46

2 Answers2

5

The easiest way would be to pass the responsibility on to whoever actually instanciates and uses instances of BaseSelectorComposer, i.e.:

public class BaseSelectorComposer<T> extends SelectorComposer<Window> {

    private HibernateSearch<T> searchObject;
    private final Class<T> theType;

    public BaseSelectorComposer(Class<T> token) {
        theType = token;
    }

    ...
    @Override
    public void doAfterCompose(Window comp) throws Exception {
        super.doAfterCompose(comp);
        this.searchObject = new HibernateSearchObject<T>(theType);
        ...
    }
    ...
}

If your BaseSelectorComposer is an abstract subclass, which is only ever used like

class IntSelectorComposer extends BaseSelectorComposer<Integer> {
    ...
}

i.e., as base class for classes, which "bind" the type parameters, there are ways to obtain the type information via reflection (though this is incredibly ugly, since this is not really well-supported in the API IMHO).

Dirk
  • 30,623
  • 8
  • 82
  • 102
1

In general, this is a hard-to-workaround scenario. Coming from .NET background, I have personally found very few cases where I could work this out, since Java does not support static generic type resolution (like for instance in .NET where you can use typeof(T)).

To work this around I recommend that you find a way to either get the class externally, or an instance of that class. A possible solution would be to change the doAfterCompose method in one of the following ways:

@Override
public void doAfterCompose(Window comp, Class<?> entityClass) throws Exception {
    super.doAfterCompose(comp);
    this.searchObject =
         new HibernateSearchObject<T>(entityClass);
    ...
}

-or-

@Override
public void doAfterCompose(Window comp, SomeEntity entity) throws Exception {
    super.doAfterCompose(comp);
    this.searchObject =
         new HibernateSearchObject<T>(entity.getClass());
    ...
}

If you cannot modify the method signature (I see it is an override), try to use a member of the class BaseSelectorComposer<T> that will hold the desired Class<?> instance.

public class BaseSelectorComposer<T> extends SelectorComposer<Window> {
    private Class<?> entityClass;

    public BaseSelectorComposer<T>(Class<?> entityClasss) {
        this.entityClass = entityClass;
    }

   ....
    @Override
    public void doAfterCompose(Window comp) throws Exception {
        super.doAfterCompose(comp);
        this.searchObject =
            new HibernateSearchObject<T>(this.entityClass);
       ...
    }
}
Ivaylo Slavov
  • 8,839
  • 12
  • 65
  • 108