javamavengenerics

maven refuses to compile generic class due to bounds, even after casting class


Here is a simplified version of the code I'm using to hold a generic list of children to a parent. Forgive me for having to rewrite this by hand instead of copy-past, There is no way to copy from machine with the issue.

MyObject<childType extends MyObject> {}

public class Model{


  HashMap<MyObject, Set<MyObject>> store= new HashMap<MyObject, Set<MyObject>>()


  public <childType extends MyObject> Set<childType> getChildren(MyObject<childType> parent)
  {

     return (Set<childType>) store.get(parent);
  }



  public void <T extends MyObject<?>> addChild(MyObject<T> parent, T child){
     Set<MyObject> childSet=store.get(parent);

     if(childSet==null){
        childSet=new Set<MyObject>();
        store.put(parent, childSet);
     }

     childSet.add(child);
 }

This builds in Eclipse without issue. However, if I clean my class files and run a maven install I get the following error:

the parameter childType is not within its bound

The error occures on the definition on getChildren. Though I have previously had a different, but similar, issue before I had paramertized the store and was casting to Set in the class calling to the store.

I understand why such an exception would occure in general, if I wasn't casting. What has me confused is that I am casting. I don't understand why it will throw an error and stop compiling rather then accepting the cast as my saying "jsut trust me, it's right" and moving on.

I believe I"m using mavin-compile-pluging version 1.6 if that matters.

ps. I have no idea whey the formatting for my code example is so ugly. If anyone can fix it or tell me how to fix it I would appreciate it. I've never had that issue before...


Solution

  • There were two solutions needed here.

    Per Louis comement by adding a generic ? parameter to MyObject definition for getChildren fixed the error message I mentioned in the original question...

    which left me with my original error message about inconvertable type showing up on the return line of the getChildren line. This was the real issue all along which my attempt to paramterize the model was trying to fix, which is why I thought the issue was with failing to cast.

    It turns out the error is a failure to cast. It seems that the compiler used by maven (I presume javac) insists on throwing an error due to my casting to a more specific set type. In effect I have a set which could contain any implimentation of MyObject, even if it isn't childType, that i"m returning as a set of childType. I understood the complain, what I didn't get is why would it happen when I was cast. Short answer, javac just insists on throwing an error here, while the eclipse compiler (properly, in my mind) returns only a warning and keeps running. This is why I only saw the error intermittently when running maven, Eclipse compiler had no issue with compiling it, it was only when I ran maven that I ended up swithing compilers to javac. I would argue this is bad and confusing behavior in the javaC implementation if it refuses to accept an explicit cast just because it may be wrong.

    Once I confirmed my understanding of the situation was correct, ie the compiler was just complaining about something I think it shouldn't rather then a real error, I put in my own hack to satisfy the compiler. Below is the fix to both issues:

      public <childType extends MyObject<?>> Set<childType> getChildren(MyObject<childType> parent)
      {
    
         return (Set<childType>) (Set) store.get(parent);
      }
    

    Your see a double cast in set. The first cast makes javaC 'forget' that my Set had a parameterized type of MyObject. Then it will allow me to cast the set to a specific parameterized type of Set because it doesn't 'know' I'm casting from the less-exact paramterized type of Set. Of course casting from Set means casting from an even less exact definition of set (I could have an Enum or Float in there) to my specific paraterized type; but javaC is fine with that. Yeah the fact that it throws an error on what should be a warning at most (including discarding annotations taht say to ignore the warning) still bugs me....