Home > Net >  Implement generic method with extended type
Implement generic method with extended type

Time:10-28

The basic idea is that I have an interface that transforms data into different data, and I want to use this interface to transform a specific subset of data.

public static interface Data<D> {
    // transform the data into different data
    <T> Data<T> transform(Function<D,T> transformer);
}

// "Something" that has been labeled
public static interface Labeled {
     String getLabel();
}

// class intended to use the Data<D> interface to transform labeled data specifically
public static class LabeledData<L extends Labeled> implements Data<L> {
    public final L labeledData;
    public LabeledData(L labeledData) {
        this.labeledData= labeledData;
    }

    // of course this will not compile because it does not override 
    // <T> Data<T> transform(Function<D,T> transformer);
    @Override
    public <T extends Labeled> LabeledData<T> transform(Function<L,T> transformer) {
        return new LabeledData<>(transformer.apply(labeledData));
    }
}

Is there anyway to either redeclare Data.transform or rearrange LabeledData to acomplished the desired functionality and flow?

I understand I "could" create LabeledData.transformLabled(...) and define the original transform to somehow cast to LabledData or throw an exception, but that doesn't sound like a very good solution.

I could also pass in a T LabeledData<L extends Labeled, T extends Labeled> but I think that would limit the usage to one trasnform type at a time, unless there is some creative way to do it.

CodePudding user response:

You can add an extra type paramter to Data:

public interface Data<TData, TBound> {
    <TTarget extends TBound> Data<TTarget, TBound> transform(Function<TData, TTarget> transformer);
}

TBound is used as the bound for the method's type parameter, TTarget.

Now the label data class' transform would override the interface method:

public static class LabeledData<TLabel extends Labeled> implements Data<TLabel, Labeled> {
    public final TLabel labeledData;
    public LabeledData(TLabel labeledData) {
        this.labeledData= labeledData;
    }

    @Override
    public <TTarget extends Labeled> LabeledData<TTarget> transform(Function<TLabel, TTarget> transformer) {
        return new LabeledData<>(transformer.apply(labeledData));
    }
}

Notice that if you have a bunch of Data with different TBound types in a list, you cannot apply the same transformation to each of them using e.g. map:

// assume that data1, data2, data3 all have different TBounds
List<Data<String, ?>> list = List.of(data1, data2, data3);

list.stream.map(x -> x.transform(y -> f(y))).toList();

Whatever f(y) returns, this is not type safe to do.

  • Related