bilarsen
bilarsen

Reputation: 85

Java generics and reflection: class loading

I am given some classes that are unknown to me. Some of them are shown as an example:

class Paper {}

class Bakery {}

class Cake extends Bakery {}

class ReflexiveBaker {

  /**
   * Create bakery of the provided class.
   * 
   * @param order class of bakery to create
   * @return bakery object
   */
  public Object bake(Class order) {
    // Add implementation here
  }

}

The task is to redesign method signature types if needed and to add implementation. The bake method should conform to the following:

Whatever I've tried I'm getting an error: Main.java:: error: incompatible types: Object cannot be converted to Cake Cake cake = baker.bake(Cake.class);

The best I've come up with is this:

public Object bake(Class<? extends Bakery> order) throws Exception {
        return order.getDeclaredConstructor().newInstance();
}

I know that it's wrong but I'm completely stuck here. Could someone please explain what's going on?

Upvotes: 5

Views: 307

Answers (1)

Ravindra Ranwala
Ravindra Ranwala

Reputation: 21124

Your methods return type is java.lang.Object and the compiler can't vouch that the return value is of type Cake unless you convince the compiler by adding an explicit unchecked cast like this.

Cake cake = (Cake) ReflexiveBaker.bake(Cake.class);

This unchecked cast is error prone and awkward. Say you have another class called Bread that is a subtype of Bakery and you pass that class instance expecting Cake as the return type. The above statement still compiles, but throws a ClassCastException at runtime.

A much better approach is to generify the method using a bounded type parameter such a way that it accepts only sub types of Bakery and returns the same type as the type parameter of the class object provided. Here's one such attempt.

static class ReflexiveBaker {
    public static <T extends Bakery> T bake(Class<T> order) {
        try {
            return order.getDeclaredConstructor().newInstance();
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException
                    | InvocationTargetException e) {
            throw new AssertionError("Class could not be instantiated.", e);
        }
    }
}

Upvotes: 6

Related Questions