2

I got a Generic GuiComponent class:

public abstract class GuiComponent<THIS extends GuiComponent<THIS>> extends Gui {
    //...
}

(If you ask youself, what this type parameter is doing, look at Calling a Generic Interface Method does not work)

This class got a bunch of component subclasses like this:

public class ConcreteComponent extends GuiComponent<ConcreteComponent> {
    //...
}

They all got renderers:

public interface ComponentRenderer<T extends GuiComponent<T>> {
    //...
}

wich have concrete implementations:

public class FlatConcreteComponentRenderer implements ComponentRenderer<ConcreteComponent> {
    //...
}

But now I got the following class:

public class GuiListBox<U> extends GuiComponent<GuiListBox<U>> {
    //...
}

which is generic itself. This leads to the following Renderer Implementation:

public class FlatListBoxRenderer implements ComponentRenderer<GuiListBox<?>> {
    //...
}

Because the renderer do not need the type of the listbox AND shall be used for ALL types of listboxes, I use the wildcard, so I do not have to care about the type. Inside the draw method of the renderer, the list elements just shall be treated as objects and toString() is called. But this implementation does not work:

Error:(21, 73) java: type argument [...]components.GuiListBox is not within bounds of type-variable T

I need to add a type to the renderer, just to use it for GuiListBox, then it compiles:

public class FlatListBoxRenderer<T> implements ComponentRenderer<GuiListBox<T>>

But this is not very useful, because the same renderer instance shall be handled to all ListBoxes by default. Why does this error occure, though my IDE (IntelliJ IDEA) does not mark this, but fails building?

EDIT #1: I use maven to compile the project, but neither my IDE nor maven are able to compile the class. Anyways, here is my pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.cydhra</groupId>
    <artifactId>Utility</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>

    </build>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.2</version>
        </dependency>
    </dependencies>
</project>

Maven outputs the exact same error as my IDE build. To clarify: The Code works, if I add a type to the Renderer, but this wont work for me, because the renderer shall be added to all List, despite the type of list. That is why I want to use the wildcard.

EDIT #2: I changed the grammar flow of my description and added a code snippet to clearify when the error occurs, and when the code compiles.

EDIT #3: Since the comments and first answer tried to reproduce and do research on my "bug", here are the results so far:

http://mail.openjdk.java.net/pipermail/compiler-dev/2015-June/009604.html

Someone was reporting a bug in Java Compiler, where the following Statement, which is basically my problematic statement:

class C1<T extends C1<T>> {}
class C2<U> extends C1<C2<U>> {}

C1<? extends C2<String>>
C1<? extends C2<?>>

Did NOT throw a compiler error, though the bug reporter was mentioning some parts of the JLS (Java Language Specification), which are violated of those constructions. The mentioned parts of the specification were dealing with Bbund intersections, so generics with multiple bounds:

class D<T extends T1 & T2 & T3...>

(if I understood that correctly). Maurizius, the guy who has his hands on Java generics, replied, that indeed, the specification where unclear at that point and so the construct was made to result in a compile time error. I personally do not understand this, because I cannot see any violation of the type bounds here, but I resigned and made my ListBoxRenderer look like this:

public class FlatListBoxRenderer implements ComponentRenderer<GuiListBox<Object>> {

    public void draw(final GuiListBox<Object> component) {
        //...
    }
}

I thought, since the renderer doesn't care about the list content at all, I could just give a unspecific type argument and use the Renderer for any purpose later. But now I come to the following error:

I got a method somewhere else in my project:

public <T extends GuiComponent<T>> void setComponentRenderer(final Class<T> componentClass,
                                                                 final ComponentRenderer<T> renderer)

this method assignes a Renderer to a class of GuiElements, so all instances of the GuiElements get a renderer by default. The method call

this.setComponentRenderer(GuiListBox.class, new FlatListBoxRenderer());

fails, because:

Inferred Type java.lang.Object for type parameter T is not within bounds; should extend [...]GuiComponent<java.lang.Object>

This error message does not make sense to me either, and slowly I get really confused (I btw know, that Java Generics aren't a nice feature of this language and many other languages offer far better Generics, which are runtime features and not only code style features. But that's another story)

My FlatListBoxRender DOES indeed have its type parameter within bounds, because the type is GuiListBox, which in my understanding extends GuiComponent (which isn't right in this place either, because GuiComponent is indeed bounded, but this bound is fullfilled by GuiListBox' declaration):

public class GuiListBox<U> extends GuiComponent<GuiListBox<U>> {}

I know my constructions are very complex, but Java isn't designed to just accept ArrayList, it should handle more than one Generic as well.

So, if anyone got solutions to my problem, please let me know. In Addition: Here is my full project code by the way: https://github.com/Cydhra/Util/tree/master/src/main/java/de/cydhra/customgui

You can find all the GuiComponents in the package components, all the renderer implementations in renderer.defaults, and the instances of the renderers in renderer.theme

19
  • This is not clear. If this code works, then what is the code which doesn't work for you?
    – Alma Alma
    Commented Jun 29, 2016 at 23:45
  • Please also post the code where your component renderer is using those listboxes
    – Alma Alma
    Commented Jun 29, 2016 at 23:46
  • The code does not work. It doesn't compile. There is no code in the renderer using the listboxes yet. It simply doesn't compile.
    – Cydhra
    Commented Jun 29, 2016 at 23:49
  • Well that's strange. I tried your code and it compiles for me without any warning or error in Java 8.
    – Alma Alma
    Commented Jun 29, 2016 at 23:52
  • I've tried to compile it with maven: Source and Target 1.8 - same error. My IDE is IntelliJ IDEA, Java Version 1.8_51. IDEA isn't showing a syntax error or warning about this, and I dont see, why the wildcard, that has nothing to do with the bound of T shouldn't work...
    – Cydhra
    Commented Jun 29, 2016 at 23:55

1 Answer 1

2

OK, I found it I think. So both eclipse and intellij idea got the generics wrong. (Which is not a surprise IMHO since it's very easy to get confused)

So there is/was a bug intellij idea which prevents it from showing any error: Java code that does not compile with JDK 8, but IntelliJ does not report an error

And there is/was a similar error in eclipse: Discrepancy between Eclipse compiler and javac - Enums, interfaces, and generics

I hope it will help those people who will scratch their head in the future.

3
  • Yeah, that is exactly the bug. But does anyone know why this bug occures, though the code would make sense and can anyone give a hint, how to fix, bypass or workaround this?
    – Cydhra
    Commented Jun 30, 2016 at 8:56
  • Ok, since I researched a lottle on you links and discussions on them, it seems, that this construct, I was searching once were able to compile, but differs from specification in some point, so it was fixed and forbidden. I personally do not understand why this was done, because I don't see, where there's a problem and for me, this isn't a theoretically construct but I do want to implement and use those features, which are now disabled. Sad story...
    – Cydhra
    Commented Jun 30, 2016 at 9:02
  • @Cydhra Well this happens sometimes. At least you know what caused the strange behavior. If you think this answered your question "Why does this error occure, though my IDE (IntelliJ IDEA) does not mark this, but fails building?" then please mark it accepted. Happy coding!
    – Alma Alma
    Commented Jun 30, 2016 at 12:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.