Reputation: 1549
I'm trying to make a parent class for converters avoiding repeated code, so I started doing the java abstract class I provide here:
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
public abstract class AbstractUIConverter {
protected abstract <UIO, DTO> DTO toDto(final UIO input);
protected abstract <DTO, UIO> UIO toUIO(final DTO input);
protected <UIO, DTO> List<DTO> toDtoList(final List<UIO> inputList) {
return convertList(inputList, true);
}
protected <DTO, UIO> List<UIO> toUIOList(final List<DTO> inputList) {
return convertList(inputList, false);
}
private <I, O> List<O> convertList(final List<I> inputList, final boolean toDto) {
List<O> returnList;
if(CollectionUtils.isNotEmpty(inputList)) {
returnList = new ArrayList<O>(inputList.size());
O temp;
for (final I inputElem : inputList) {
if(toDto) {
temp = toDto(inputElem);
} else {
temp = toUIO(inputElem);
}
returnList.add(temp);
}
} else {
returnList = new ArrayList<O>(0);
}
return returnList;
}
}
The problem is when coming to subclassing. When I make a subclass extending this class and replace the type of the input parameter called 'input' in the method signature to override either toDto() or toUIO() like this:
@Override
protected <UIO, DTO> DTO toDto(SomeTypeUIO input) {
it appears a message:
The method toDto(SomeTypeUIO) of type SubclassConverter must override or implement a supertype method
If I replace in the the first type:
protected <SomeTypeUIO, DTO> DTO toDto(SomeTypeUIO input) {
it appears this warning:
The type parameter SomeTypeUIO is hiding the type
which obviously is what I don't want.
I have tried parameterizing AbstractUIConverter but this is worse. I also have tried messing with "extends" inside syntax.
My goal is to define the types in the subclass, so the functions for converting lists are all made in the parent.
I would appreciate help and advice, or some resources for looking in the web.
Upvotes: 0
Views: 125
Reputation: 11740
The right approach would be:
public abstract class AbstractUIConverter<UIO, DTO> {
protected abstract DTO toDto(final UIO input);
protected abstract UIO toUIO(final DTO input);
protected List<DTO> toDtoList(final List<UIO> inputList) {
return convertList(inputList, this::toDto);
}
protected List<UIO> toUIOList(final List<DTO> inputList) {
return convertList(inputList, this::toUIO);
}
private <I, O> List<O> convertList(final List<I> inputList, final Function<I, O> function) {
if(inputList.isEmpty()) {
return Collections.emptyList();
}
List<O> returnList = new ArrayList<>(inputList.size());
for(I input : inputList) {
returnList.add(function.apply(input));
}
return returnList;
}
}
You already have a distinction in your method call how to transform your data.
< Java 8:
public abstract class AbstractUIConverter<UIO, DTO> {
protected abstract DTO toDto(final UIO input);
protected abstract UIO toUIO(final DTO input);
protected List<DTO> toDtoList(final List<UIO> inputList) {
return convertList(inputList, new Function<UIO, DTO>() {
@Override
public DTO apply(UIO input) {
return AbstractUIConverter.this.toDto(input);
}
});
}
protected List<UIO> toUIOList(final List<DTO> inputList) {
return convertList(inputList, new Function<DTO, UIO>() {
@Override
public UIO apply(DTO input) {
return AbstractUIConverter.this.toUIO(input);
}
});
}
private <I, O> List<O> convertList(final List<I> inputList, final Function<I, O> function) {
if(inputList.isEmpty()) {
return Collections.emptyList();
}
List<O> returnList = new ArrayList<>(inputList.size());
for(I input : inputList) {
returnList.add(function.apply(input));
}
return returnList;
}
}
Upvotes: 1