Diogo Soares
Diogo Soares

Reputation: 168

Java Generics - Unchecked cast from "capture#1 of ?" to "A"

I have 2 warnings:

I know that the class is in fact an Event.

Where Event is an Interface and Exhibition and Congress both implement the Event interface.

public static <A extends Event> A copy(A event) {
        Class<?> eventType = event.getClass(); // --> Warning 1
        return (A) eventType.getConstructor(eventType).newInstance(event);
    return event;
}

The second Warning:

public static <A extends Event> A create(EventType type) {
    if(type == EventType.CONGRESS){ 
        return (A) new Congress() // --> Warning 2
    }else(){
        return (A) new Exhibition() // --> Same as warning 2 but for Exibition
    }
}

Now the question is: How can i resolve this two warnings without using:

@SuppressWarning("unchecked")

Upvotes: 1

Views: 3816

Answers (4)

Sweeper
Sweeper

Reputation: 273610

Seems like you are misusing generics. If the method gets to decide what type to return, you should not use generics. Generics are used when the caller decides what type to return.

So create should be like this:

public static Event create(EventType type) {
    if(type == EventType.CONGRESS){ 
        return new Congress();
    }else {
        return new Exhibition();
    }
}

For the first warning, you can do something like this.

public static <A extends Event> A copy(A event) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    return (A) event.getClass().getConstructor(event.getClass()).newInstance(event);

}

Upvotes: 2

atmin
atmin

Reputation: 370

I would recommend using TypeTags aka ClassTags. Something like:

public static <A extends Event> Optional<A> create(Class<A> classTag) {
    try {
        return Optional.of(classTag.newInstance());
    } catch (InstantiationException | IllegalAccessException e) {
        return Optional.empty();
    }
}

Call it like so:

public static void main(String[] args) {
    Optional<Exhibition> e = create(Exhibition.class);
    e.ifPresent(System.out::println);
}

Upvotes: 0

Turing85
Turing85

Reputation: 20195

You can resolve the first warning by declaring eventType as Class<? extends A>. This makes the cast to A superfluous.

If you cannot change the return type of the first method, there is no option to resolve this compilation issue without resorting to casting. The compilation issue can be resolved by changing the return type of the method to Event. If you change the return type to Event, you can fully drop the generic parameter:

public static Event copy(Event e)
        throws NoSuchMethodException,
            IllegalAccessException,
            InstantiationException,
            InvocationTargetException {
    Class<? extends Event> cls = e.getClass();
    return cls.getConstructor(cls).newInstance();
}

For the second warning, you can also fully drop the generic type of the method:

public Event create(EventType type) {
    if (type == EventType.CONGRESS) {
        return new Congress();
    } else {
        return new Exhibition();
    }
}

This assumes that Congress extends Event and Exhibition extends Event.

Upvotes: 0

daniu
daniu

Reputation: 15018

Why would you make this a static method?

public static <A extends Event> A copy(A event) {
        Class<?> eventType = event.getClass(); // --> Warning 1
        return (A) eventType.getConstructor(eventType).newInstance(event);
    return event;
}

You have an instance of Event, let the Event class be able to create a copy of itself.

abstract class Event<E extends Event<E>> {
    public E createCopy(E toCopy);
}

with

class Exhibition extends Event<Exhibition> {
    // ...
    public Exhibition createCopy() {
        return new Exhibition(this); 
    }
}

What you can to get rid of the second warning is adjusting EventType to

public enum EventType {
    CONGRESS { public Event createEvent() { return new Congress(); }},
    EXHIBITION { public Event createEvent() { return new Exhibition(); }};

    public abstract Event createEvent();
}

which will result in

public static Event create(EventType type) {
    return type.createEvent();
}

If it's really necessary to know the exact type of event that's returned, you should really reconsider the design at this point.

Upvotes: 0

Related Questions