0

at the moment i am trying to build a Java class which is able to creat a random Object. I tryed it with Factory Pattern and the abstract Product Interface is like :

public interface ObjectFactory<T>
{
    T createObject();
}

but when i am trying to implement a concret generic Product it dosn't work. Here is the Code of my concrete Product:

public class GenericFactory implements ObjectFactory<T> {

    @Override
    public T createObject()
    {
        return new T();
    } 
}

IntelliJ says: "Cannot resolve symbol T"

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • 3
    How it supposed to know *which* "random object" to create? – chrylis -cautiouslyoptimistic- Sep 13 '18 at 13:16
  • Use `GenericFactory` and `public T` – S.K. Sep 13 '18 at 13:17
  • 2
    Why do you need this, rather than using the standard [`Supplier` class](https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html)? – Andy Turner Sep 13 '18 at 13:19
  • 1
    "IntelliJ says: "Cannot resolve symbol T"" because `T` needs to be either a class name that you've imported (or is in the same package), or a type variable that you declare on `GenericFactory`. – Andy Turner Sep 13 '18 at 13:21
  • 1
    This is useful: https://stackoverflow.com/questions/299998/instantiating-object-of-type-parameter – Rahim Dastar Sep 13 '18 at 13:22
  • It won't work with `GenericFactory` as well. – stevecross Sep 13 '18 at 13:22
  • related: https://stackoverflow.com/questions/34078846/java-creating-a-new-object-with-unknown-type – dustytrash Sep 13 '18 at 13:25
  • When you make concrete implementations you need to specify the exact object you want to create. Java implements generics using type erasure, which means that the compiler doesn't know which type of object to instantiate in this case. Try making the code more specific (eg. class concreteFactory implements AbstractFactory) – Bloodeye Sep 13 '18 at 13:27

2 Answers2

0

This is not a valid implementation of a generic Class.

The Concrete class needs to specify which object the Type Variable T is.

The code should look more like this :

public class GenericFactory implements ObjectFactory<MyClass> {

    @Override
    public MyClass createObject() {
        return new MyClass();
    }

}
stevecross
  • 5,588
  • 7
  • 47
  • 85
Bloodeye
  • 94
  • 6
0

Java uses type erasure for generics. Thus the JVM can not know which type T actually is at runtime.

You could create a generic factory using refelection, but this is really ugly. If you want to use generic factories in production go for Spring or something similar.

public interface ObjectFactory<T> {

    T createObject(Class<? extends T> type);

}

public class GenericFactory<T> implements ObjectFactory<T> {

    public T createObject(Class<? extends T> type) {
        try {
            Constructor<? extends T> constructor = type.getDeclaredConstructor();

            constructor.setAccessible(true);

            return constructor.newInstance();
        } catch (Throwable e) {
            throw new InstantiationError("Can not create an object of class " + type.getName());
        }
    }

}

public class Main {

    public static void main(String[] args) {
        GenericFactory<Car> carFactory = new GenericFactory<>();
        Car car = carFactory.createObject(Car.class); // works

        GenericFactory<Car> bikeFactory = new GenericFactory<>();
        Bike bike = bikeFactory.createObject(Bike.class); // throws exception
    }

    private static class Car {}

    private static class Bike {

        private String color;

        Bike(String color) {
            this.color = color;
        }

    }

}
stevecross
  • 5,588
  • 7
  • 47
  • 85