I have the following classes
public class PathPart {
private final String pathPart;
public PathPart(String pathPart) {
this.pathPart = pathPart;
}
public String getPathPart() {
return pathPart;
}
}
public class Path {
private final List<? extends PathPart> pathParts;
public Path(String path) {
this.pathParts = getPathParts(path);
}
public List<? extends PathPart> getPathParts() {
return this.pathParts;
}
protected List<? extends PathPart> getPathParts(String path) {
return Arrays.stream(path.split("/")).map(PathPart::new).collect(Collectors.toList());
}
}
public class FooBarPathPart extends PathPart {
public FooBarPathPart(String pathPart) {
super(isFoo(pathPart) ? "bar" : pathPart);
}
private static boolean isFoo(String pathPart) {
return "foo".equals(pathPart);
}
}
public class FooBarPath extends Path {
public FooBarPath(String path) {
super(path);
}
@Override
public List<FooBarPathPart> getPathParts() {
// UNCHECKED CAST HERE
return (List<FooBarPathPart>) super.getPathParts();
}
@Override
protected List<FooBarPathPart> getPathParts(String path) {
return Arrays.stream(path.split("/")).map(FooBarPathPart::new).collect(Collectors.toList());
}
}
where I'd like to capture the structure of a filesystem path /my/path/to/a/directory
in my Path
object, which stores my
, path
, to
, a
, directory
each as a PathPart
object.
Now, I have a subclass of PathPart
called FooBarPathPart
, where if the path part is equal to foo
, then I want it to change it to bar
. And, I also have FooBarPath
which is a subclass of Path
, which stores a list of FooBarPathPart
. So /my/path/to/foo/directory
will essentially become /my/path/to/bar/directory
My issue is that I get an Unchecked cast
warning from List<? extends PathPart>
to List<FooBarPath>
in my getPathParts()
method in the FooBarPath
class.
Is there a way to get rid of this unchecked cast warning properly? Is my usage of the wildcard correct here? Or is there a better way to approach this problem that doesn't involve the wildcard? I'm not very familiar with generics
CodePudding user response:
Thanks for the help Thomas
I have solved the problem using generics and using a creator function. Here's the full solution:
public class PathPart {
private final String pathPart;
public PathPart(String pathPart) {
this.pathPart = pathPart;
}
public String getPathPart() {
return pathPart;
}
}
public class FooBarPathPart extends PathPart {
public FooBarPathPart(String pathPart) {
super(isFoo(pathPart) ? "bar" : pathPart);
}
private static boolean isFoo(String pathPart) {
return "foo".equals(pathPart);
}
}
public abstract class AbstractPath<T extends PathPart> {
private final List<T> pathParts;
private final Function<String, T> factory;
public AbstractPath(Function<String, T> factory, String path) {
this.factory = factory;
this.pathParts = createPathParts(path);
}
public List<T> createPathParts() {
return this.pathParts;
}
private List<T> createPathParts(String path) {
return Arrays.stream(path.split("/")).map(factory).collect(Collectors.toList());
}
}
public class Path extends AbstractPath<PathPart> {
public Path(String path) {
super(PathPart::new, path);
}
}
public class FooBarPath extends AbstractPath<FooBarPathPart> {
public FooBarPath(String path) {
super(FooBarPathPart::new, path);
}
}