Marco
Marco

Reputation: 41

Java generics factory pattern

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

Answers (2)

davioooh
davioooh

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

Olivier Gr&#233;goire
Olivier Gr&#233;goire

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

Related Questions