Opal Opal - 1 year ago 51
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 Source

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(""));
    }
}