Type issue when using Java library: polymorphic Java class

Hello,

I am trying to recode the examples of the Hansolo’s char library using JDK 21. I have coded quite a few examples, but cannot solve an issue in an example. The code can be found here. To try and run the example we execute:

./mill -i hansolo.bar.runMain hansolo.charts.PanelBarChartTest

The relevant code snippet is:

    override def init() = {
        val categories: List[DayOfWeekCategory] = List.of(Categories.MONDAY, Categories.TUESDAY, Categories.WEDNESDAY, Categories.THURSDAY, Categories.FRIDAY, Categories.SATURDAY, Categories.SUNDAY)
        val listOfSeries: List[ChartItemSeries[ChartItem]] = new ArrayList[ChartItemSeries[ChartItem]]()
        val ss = 0 until 3
        for (s <- ss) {
            val serverNo: Int = s
            val series: ChartItemSeries[? <: ChartItem] = ChartItemSeriesBuilder.create().name("This week " + serverNo).build()
            categories.forEach(category => {
                val item: ChartItem = ChartItemBuilder.create().name(series.getName() + " " + category.getName(TextStyle.SHORT, Locale.US)).category(category).value(RND.nextDouble() * 100).fill(Color.ORANGE).build()
                series.getItems().add(item)
            })
            listOfSeries.add(series)
        }
...

The relevant errors are:

[error] 69 |                series.getItems().add(item)
[error]    |                                      ^^^^
[error]    |                  Found:    (item : eu.hansolo.fx.charts.data.ChartItem)
[error]    |                  Required: series.T
[error]    |
[error]    | longer explanation available when compiling with `-explain`
[error] -- [E007] Type Mismatch Error: /home/hmf/VSCodeProjects/javaFXClientMill/hansolo/bar/src/PanelBarChartTest.scala:71:29 
[error] 71 |            listOfSeries.add(series)
[error]    |                             ^^^^^^
[error]    |Found:    (series :
[error]    |  eu.hansolo.fx.charts.series².ChartItemSeries[?
[error]    |     <: eu.hansolo.fx.charts.data.ChartItem]
[error]    |)
[error]    |Required: eu.hansolo.fx.charts.series².ChartItemSeries[eu.hansolo.fx.charts.data.ChartItem
[error]    |  ]
[error]    |
[error]    |where:    series  is a value in an anonymous function in method init
[error]    |          series² is a package in package eu.hansolo.fx.charts
[error]    |
[error]    | longer explanation available when compiling with `-explain`

The library code is here.

I have made several attempts at explicitly setting the types but have not succeeded. Can anyone tell me how to set these types?

TIA

You’re defining series to be a series of some unspecified type of elements, but the type is a subclass of, or is, ChartItem. This is odd anyway, because as far as I can tell, ChartSeries has no subclasses in the chart library.

That won’t work because each piece-by-piece addition of a ChartItem doesn’t know what specific type series expects its elements to conform too. Maybe it’s a ChartItemSeries[FooChartSeries], or maybe it’s a ChartItemSeries[BarChartSeries]. The compiler doesn’t know because you used a wildcard type.

My advice is, just define series to be a plain ChartItemSeries[ChartItem].

You’ll probably need to do some creative casting to initialise series because the builder yields a generic type without type parameters. Sigh.

@sageserpent-open The solution you suggest is what I initially tried, but won’t work either. Her is the error:

[error] 66 |            val series: ChartItemSeries[ChartItem] = ChartItemSeriesBuilder.create().name("This week " + serverNo).build()
[error]    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |Found:    eu.hansolo.fx.charts.series.ChartItemSeries[?]
[error]    |Required: eu.hansolo.fx.charts.series.ChartItemSeries[eu.hansolo.fx.charts.data.ChartItem]

The problem seems to stem from this Java call:

    public final ChartItemSeries build() {
        final ChartItemSeries control = new ChartItemSeries();

One can see that the type is not explicitly set.

What is more, the Java class is declares as:

public class ChartItemSeriesBuilder<B extends ChartItemSeriesBuilder<B>>

which is instantiated via this call:

 public static final ChartItemSeriesBuilder create() {
        return new ChartItemSeriesBuilder();
    }

which also does not set the type.

So I am a little lost here.

You’re encountering the problem I anticipated earlier. In this case, put an .asInstanceOf[ChartSeries[ChartItem]] at the end of the initialiser and you should be OK.

I’ve had to do this with other Java libraries, the Caffeine builder has similar issues as does something or other in Kryo…

2 Likes

Thanks. Will do.