JDK-8193583 : Generic types have to be casted to proper type
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8,9,10
  • Priority: P3
  • Status: Closed
  • Resolution: Not an Issue
  • OS: generic
  • CPU: x86_64
  • Submitted: 2017-12-14
  • Updated: 2018-04-10
  • Resolved: 2018-04-10
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11
11Resolved
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_152"
Java(TM) SE Runtime Environment (build 1.8.0_152-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Darwin iMac-Marcin 17.3.0 Darwin Kernel Version 17.3.0: Thu Nov  9 18:09:22 PST 2017; root:xnu-4570.31.3~1/RELEASE_X86_64 x86_64

A DESCRIPTION OF THE PROBLEM :
Returned generic type which is declared from inner public classes loses original type.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I provided code below


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Error:(7, 55) java: cannot find symbol
  symbol:   method getActionButtonEvent()
  location: class com.marurban.BaseViewModel<com.marurban.FavoriteLeaguesViewModel.Accessor,com.marurban.FavoriteLeaguesViewModel.ViewEvents,com.marurban.FavoriteLeaguesViewModel.FlowEvents>.FlowEvents

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class Main {

    public static void main(String[] args) {

        new FavoriteLeaguesViewModel().getFlowEvents().getActionButtonEvent();
    }
}

public abstract class BaseViewModel<FlowEvents extends BaseViewModel.FlowEvents> {

    private FlowEvents flowEvents;

    public BaseViewModel() {
        flowEvents = createFlow();
    }

    protected abstract FlowEvents createFlow();

    public FlowEvents getFlowEvents() {
        return flowEvents;
    }

    public  class  FlowEvents {
    }
}

public abstract class FavoritesViewModel<FlowEvents extends FavoritesViewModel.FlowEvents>
        extends BaseViewModel<FlowEvents> {

    List list;

    public FavoritesViewModel() {
        super();
    }

    public abstract class FlowEvents extends BaseViewModel.FlowEvents {

        public List getActionButtonEvent() {
            return list;
        }
    }
}


public class FavoriteLeaguesViewModel extends FavoritesViewModel<FavoriteLeaguesViewModel.FlowEvents> {

    public FavoriteLeaguesViewModel() {
        super();
    }

    @Override
    protected FlowEvents createFlow() {
        return new FlowEvents();
    }

    public class FlowEvents extends FavoritesViewModel.FlowEvents {

    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
You need to explicitly cast to proper class.

public class Main {

    public static void main(String[] args) {
        FavoriteLeaguesViewModel viewModel = new FavoriteLeaguesViewModel();
        FavoriteLeaguesViewModel.FlowEvents flowEvents = (FavoriteLeaguesViewModel.FlowEvents) viewModel.getFlowEvents();
        flowEvents.getActionButtonEvent();
    }
}



Comments
This is not a bug - in fact the program relied on a non-conformance that was fixed during JDK 8 development. The core issue is that the class BaseViewModel uses the 'FlowEvents' name for two purposes: 1) type parameter name 2) static class declaration name Now, (1) is in scope in the class declaration: " The scope of a class's type parameter (��8.1.2) is the type parameter section of the class declaration, the type parameter section of any superclass or superinterface of the class declaration, and the class body. " but (2) is also in scope: " The scope of a declaration of a member m declared in or inherited by a class type C (��8.1.6) is the entire body of C, including any nested type declarations. " Hence we have to resort to the shadowing rules: " A declaration d of a type named n shadows the declarations of any other types named n that are in scope at the point where d occurs throughout the scope of d. " That is, the nested class name shadows the type parameter name with same name in the body of BaseViewModel. This means that all references to FlowEvents occurring throughout BaseViewModel will be interpreted as references to the static nested class. Hence the resulting error (the nested class BaseViewModel.FlowEvents has no method named getActionButtonEvent()).
10-04-2018

This is a regression starting from 8 and exist in 9 and latest builds of 10 (10 ea b35) Below is the result executed on 10 == -sh-4.2$ /scratch/fairoz/JAVA/jdk10/jdk-10-ea+35/bin/javac *.java Main.java:5: error: cannot find symbol new FavoriteLeaguesViewModel().getFlowEvents().getActionButtonEvent(); ^ symbol: method getActionButtonEvent() location: class BaseViewModel<FavoriteLeaguesViewModel.FlowEvents>.FlowEvents Note: FavoriteLeaguesViewModel.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 1 error == If we explicitly typecast to proper cast, there won't be any issue FavoriteLeaguesViewModel viewModel = new FavoriteLeaguesViewModel(); FavoriteLeaguesViewModel.FlowEvents flowEvents = (FavoriteLeaguesViewModel.FlowEvents) viewModel.getFlowEvents(); flowEvents.getActionButtonEvent(); Will result no error Below are the results 7u80 -Pass 8 ea b02 - Pass 8 ea b131 (GA) - Fail 8u162 - Fail 9 GA - Fail 10 ea b35 - Fail
15-12-2017