Opal Opal - 27 days ago 7
Java Question

Why this converter needs casting?

I need to implement an enum to enum converter in java:

Enum_2
>
Enum_1
and I'd like to do it in generic way.

So I defined an interface:

interface LabelAware<T extends Enum> {
String getLabel();

T getObject();
}


and
Enum_1
:

enum Enum_1 {
A, B;

String getValue() {
return "whatever";
}
}


and
Enum_2
which implements
LabelAware
and need to be converted to
Enum_1
:

enum Enum_2 implements LabelAware<Enum_1> {
C("c", Enum_1.A), D("d", Enum_1.B);

private final String label;
private final Enum_1 object;

Enum_2(String label, Enum_1 object) {
this.label = label;
this.object = object;
}

public String getLabel() {
return label;
}

public Enum_1 getObject() {
return object;
}
}


Finally, here's a generic converter (
List.ofAll()
comes from javaslang):

class Converter<S extends LabelAware, D extends Enum> {

private S[] values;

Converter(S[] values) {
this.values = values;
}

D map(String label) {
return (D) List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
}


And a main method:

public class Main {
public static void main(String[] args) {
System.out.println(new Converter<Enum_2, Enum_1>(Enum_2.values()).map("c").getValue());
}
}


It all compiles and runs well, however I've no ides why I need to cast the result of
Converter.map
method to
D
, since I've declared
D
to extend
Enum
. Can it be done in a generic way without any warnings?

Answer

You have been using raw types at several places (not only the one that yshavit pointed out in the comment). Particularly, the

class Converter<S extends LabelAware, D extends Enum> 

has to be

class Converter<S extends LabelAware<D>, D extends Enum<D>>

The following should compile without warnings:

import javaslang.collection.List;

interface LabelAware<T extends Enum<?>>
{
    String getLabel();

    T getObject();
}

enum Enum_1
{
    A, B;

    String getValue()
    {
        return "whatever";
    }
}

enum Enum_2 implements LabelAware<Enum_1>
{
        C("c", Enum_1.A), D("d", Enum_1.B);

    private final String label;
    private final Enum_1 object;

    Enum_2(String label, Enum_1 object)
    {
        this.label = label;
        this.object = object;
    }

    public String getLabel()
    {
        return label;
    }

    public Enum_1 getObject()
    {
        return object;
    }
}

class Converter<S extends LabelAware<D>, D extends Enum<D>>
{

    private S[] values;

    Converter(S[] values)
    {
        this.values = values;
    }

    D map(String label)
    {
        return List.of(values)
            .find(v -> v.getLabel().equals(label))
            .map(LabelAware::getObject)
            .getOrElseThrow(() -> new RuntimeException(""));
    }
}
Comments