Chicken and the Egg

I have an abstract superclass (NGEntity) and about a dozen subclasses. Each subclass implements an interface (EntityInt) as to simplify the <T extends ENtityInt> generic definition.

publicabstractclass NGEntity{...}

publicclass NGClientextends NGEntityimplements EntityInt{

public NGClient(){...}

}

publicinterface EntityInt{/*methods all subclasses use*/}

I also have container objects using one of these subclasses, without knowing in advance which type it will contain.

publicclass Manager<Textends EntityInt>{

private T entity;

public Manager(){/*create a new empty entity here*/}

}

I'm trying to make a factory class (EntityBuilder) that can build this parametrized object for me. I first tried parametrizing this factory with one of these subclasses, so that a simple method call would return a new object of the desired type.

publicclass EntityBuilder<Textends EntityInt>{

//constructor is basically empty

public T build(){/*make new entity and return*/}

}

This would require a new instance of the factory for each different type. In my code, I don't really need to switch, so it is acceptable, but it would require a "new T()" command of something.

I've read a neat way of achieving my goal using Class<T> (where T is my parametre from above)

public T build(Class<T> cl){

return cl.newInstance();

}

This brings me back to the starting point, since to get a Class<T>, I need an instanciated object to call getClass() on.

I've even tried something like: Class<Textends EntityInt> cl=new Class<Textends EntityInt>();

but Class does not have public constructors.

Chicken and the egg, or am I just chasing my tail?

[3217 byte] By [nicfortin1342a] at [2007-11-27 9:35:11]
# 1

> This brings me back to the starting point, since to

> get a Class<T>, I need an instanciated object to call

> getClass() on.

No, you don't.

If you know the class at compile time, you can just use Whatever.class. If you don't, you can use Class.forName("Whatever").

jverda at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 2

> Class<T extends

> EntityInt> cl=;

> but Class does not have public constructors.

>

> Chicken and the egg, or am I just chasing my tail?

Class<? extends Number> clazz1 = Integer.class;

Class<? extends Number> clazz2 = (Class<? extends Number>)Class.forName("java.lang.Integer");

Note that with the second one, there's no way to avoid a warning. You'll have to ignore it or supress it.

jverda at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 3

That's my problem. I don't know at compile time which class it will be. I have a dozen or so different cases.

It is decided at run time by the user which class/object goes inside my container, so in my code I would be calling getClass() on T, a parametrized type. It gives me the "non-static call in static context" error.

calling T.class doesn't help either: "cannot select from a type variable" error.

nicfortin1342a at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 4
> That's my problem. I don't know at compile time which> class it will be. I have a dozen or so different> cases.So use the second form. Class.forName
jverda at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 5

I don't have the classname String either. I have 19 entities in total, and no way at compile time to know which class/classname I'll end up with. Otherwise I wouldn't ask the question.

one of such containers is part of my hierarchy. It contains a keyword (NGKeyword, also part of my entities) and another entity among my 19...

public class NGMLink<T extends EntityInt> extends NGEntity implements EntityInt{

private T entity;

private NGKeyWord key;

private EntityBuilder<T> bob; //my factory

public NGMLink(){

key=new NGKeyWord(); //empty keyword, no problem there

bob=new EntityBuilder<T>(); //instantiate the factory to build T types

entity=bob.build();//calling this method would return an empty entity

//(all my entities have the empty constructor)

}

}

the last way is to go all the way up the chain, find the class there, and transmit it down. My point was to avoid that extra overhead in the first place, since this factory would be used quite a few times in my final program.

nicfortin1342a at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 6
> I don't have the classname String either. But you will at runtime. Anyplace a string literal, like "abc" is used, you can also use a String variable.
jverda at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 7

Something like this perhaps?

public static <T extends EntityInt> T getType(Class<T> type)

throws InstantiationException, IllegalAccessException {

return type.newInstance();

}

Message was edited by:

prometheuzz

Nevermind, should've read the post more carefully...

prometheuzza at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 8
I'll have the class name at runtime, but it will require some overhead in bubbling it down to my factory. I wanted to avoid that, but it seems I can't. Thank you anyway
nicfortin1342a at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 9

> I'll have the class name at runtime, but it will

> require some overhead in bubbling it down to my

> factory.

I have no idea what you mean by that.

You wanted something like new Class<T>() or whatever. I showed you what you have to do to get that. I don't see any "bubbling down" there that wouldn't've been present in your way.

jverda at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 10

The code I show here is only part of the program. I didn't include it all because it wasn't really relevant. A the top level I have a GUI in which the user selects which entity he wants to create. I understand the concept of class.forName() & X.class to get the classname, but if my factory can't tell which one the user needs, I can't use it.

My "bubbling down" (what I ended up doing) is just carrying the class<T> variable from the top GUI to the factory. I wanted to avoid that because I needed to change most of my classes to accomodate that.

(The one thing I'm after, I think, is getting the classname from the T parametre. I don't actually have an object, just the <T extends EntityInt>)

Message was edited by:

nicfortin1342

nicfortin1342a at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 11
Okay, well, I totally don't understand what you're trying to do.Good luck.
jverda at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 12
nicfortin1342: If I got you right, you try something that is not possible. Generics are a compile time only feature, there are no generic parameters at runtime so there is actually no use for"getting the classname from the T parameter".
stefan.schulza at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 13

If I make 3 different factories, with 3 different parametres, I'd like each to instantiate its own kind of entity. Here's an example:

Classes Client, Document, and Item are 3 entities as above and all have a no-argument constructor.

EntityBuilder<Client> cli = new EntityBuilder<Client>();

EntityBuilder<Document> doc = new EntityBuilder<Document>();

EntityBuilder<Item> ite = new EntityBuilder<Item>();

Client one = cli.build();

Document two = doc.build();

Item three = ite.build();

my EntityBuilder.build() method would need to look like

public T build(){

//find either Class<T> cl or String cl corresponding to my T

return cl.newInstance();//or Class.forname(cl).newInstance()

}

But that's where I had my chicken/egg paradox: I can't get the instance unless i have the class, and I can't get the class unless I have some kind of instance. (Actually I could, but I would have to scrap the Generics, which defeats my purpose)

The bubbling I was talking about was simply to pass a Class<T> to my factory on construction, but that requires I carry around the Class<T> object, which again kinda defeats what I'm trying to do.

To me, eventually the T will be replaced by some class name, so why couldn't the compiler recognize that this class name would exist (any Object has a getClass() method) when that line is reached..?

So far, it seems impossible, but I'll keep looking. Thanks for those who tried to help. below is my current EntityBuilder configuration. (I really don't like it, but it's the best I got)

public class EntityBuilder<T extends EntityInt>{

private Class<T> cl;

public EntityBuilder(Class<T> c){cl=c;}

public T build(){return cl.newInstance();}

}

//it is called like so:

//EntityBuilder<Client> bob=new EntityBuilder<Client>(Class.forName("Client"));

nicfortin1342a at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 14

That does not make sense, mate. If you need to apply reflection because of not knowing the class at compile time, there is no use of generics here. At runtime, each of your factories will be an instance of the same class, namely EntityBuilder. There is no generics anymore. Java generics are no C++-Templates.

What would you need the generic information for, anyway? The factory creates instances of a class that you have no knowledge about at compile time. Where would you need "type-safe build instances" here? And if your code knows the types at compile time, there is no need for such kind of factories. You should rethink the requirements of your application.

stefan.schulza at 2007-7-12 23:01:33 > top of Java-index,Core,Core APIs...
# 15
Originally, the factory would have been able to build a batch (like, say, from a ResultSet), which in the long run would have saved me some time. Not much, but still.
nicfortin1342a at 2007-7-21 23:03:41 > top of Java-index,Core,Core APIs...