Reputation: 23
Here is what I want to do:
I have an interface Service as follows:
public interface Service<A extends Object, R extends Object> {
R run(A a);
}
Now, I want to link two such services, while keeping it generic:
public class Link<A, R> implements Service<A, R> {
private Service<A, X> s1; // fail
private Service<X, R> s2; // fail
public <X> Link(Service<A, X> s1, Service<X, R> s2) {
this.s1 = s1;
this.s2 = s2;
}
@Override
public R run(A a) {
return s2.run(s1.run(a));
}
}
The problem that I want to address is to assign a generic type X to class Link, but I want that to be inferred through its constructor and not through the class declaration.
How is it achievable?
Edit:
The way I've solved this is by a utility static method which does the linking process:
public static <A, I, R> Service<A, R> link(final Service<A, I> s1, final Service<I, R> s2) {
return new Service<A, R>() {
@Override
public R run(A a) throws Exception {
I intermediate = s1.run(a);
return s2.run(intermediate);
}
};
}
Upvotes: 2
Views: 106
Reputation: 198211
You cannot have a generic type X
that is part of your class (not selected anew for each method call) that is not part of its declaration.
Sure, you could hide the unsafe casts and be certain your program would work, but those are really your only two options in the limitations of Java's type system.
What I would do, though, is instead of providing a Link
constructor, provide the static factory method
public static <A, X, R> Service<A, R> link(Service<A, X> s1, Service<X, R> s2) {
return new Link<A, X, R>(s1, s2);
}
...ensuring that X
is automatically inferred and never escapes.
Upvotes: 4
Reputation: 3699
For better covariance you could adjust the above answers like this:
public class Link <F, X, T> implements Service <F, T> {
private final Service<F, ? extends X> from;
private final Service <X, ? extends T> to;
public Link(Service <F, ? extends X> from, Service <X, ? extends T> to) {
this.from = from;
this.to = to;
}
@Override
public T run (F input) {
return to.run (from.run (input));
}
}
Upvotes: 1
Reputation: 7322
This will work:
public class Link<A, R, X> implements Service<A, R> {
private Service<A, X> s1;
private Service<X, R> s2;
public Link(Service<A, X> s1, Service<X, R> s2) {
this.s1 = s1;
this.s2 = s2;
}
@Override
public R run(A a) {
return s2.run(s1.run(a));
}
}
Upvotes: 0