Reputation: 41
I have a trouble with the factory pattern when using generics. I have this interface, generic on everything:
public interface Connection<T> {
/* methods */
}
Obviously, I have this implementation:
public class ImplConnection<V> implements Connection<V> {
/* body */
}
Then I have this factory, that must create an instance of a connection:
public class ConnectionFactory<V, C extends Connection<V>> {
private final Class<V> contentType;
private final Class<C> connectionType;
public ConnectionFactory(Class<V> contentType, Class<C> connectionType) {
this.contentType = contentType;
this.connectionType = connectionType;
}
public C newConnection() {
try {
return connectionType.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
I'm trying to instantiate the connection at runtime using this (I'm using Integer
as parameter for the generic type):
connectionFactory = new ConnectionFactory<Integer, Connection<Integer>>(Integer.class, Connection.class);
but it says:
The constructor ConnectionFactory <Integer,Connection<Integer>>(Class<Integer>, Class<Connection>) is undefined.
Upvotes: 4
Views: 409
Reputation: 24676
When I work with generics I often use Guava TypeToken
. They are very helpful. Your class could be like this:
public class ConnectionFactory<V, C extends Connection<V>> {
private final TypeToken<V> contentType;
private final TypeToken<C> connectionType;
public ConnectionFactory() {
this.contentType = new TypeToken<V>(getClass()) {};
this.connectionType = new TypeToken<C>(getClass()) {};
}
public C newConnection() {
try {
return (C) connectionType.getRawType().newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Take a try.
Upvotes: 1
Reputation: 35417
When passing class parameters, Connection
doesn't extend Connection<Integer>
. So Class<Connection>
cannot be given as parameter to Class<? extends Connection<Integer>>
. This is what is hidden behind your error.
What you should do if you want to keep this kind of pattern is to have somehting like this:
public class IntegerConnection implements Connection<Integer> {}
This will work.
However, and generally speaking, you know that you can create a generic instance without having to type anything special?
public class ConnectionFactory {
public <T> Connection<T> newConnection() {
return new ConnectionImpl<T>();
}
}
And you can use it like this:
Connection<Integer> connection = connectionFactory.newInstance();
Upvotes: 4