Bind two generic types - java

I have a question regarding generics.
I have the following interfaces:
public interface InterfaceA<B extends InterfaceA.InterfaceB> {
public interface InterfaceB<A extends InterfaceA> {
void setA(A a);
}
}
And the following abstract implementation of InterfaceA:
public abstract class AImplOne<B extends InterfaceA.InterfaceB> implements InterfaceA<B> {
private final B b;
public AImplOne(B b) {
this.b = b;
b.setA(this); // <-- Unchecked call...
}
}
Its clear to me, that the call b.setA(this) is unchecked - but I don't like it, so I tried a second abstract implementation:
public abstract class AImplTwo<A extends InterfaceA, B extends InterfaceA.InterfaceB<A>> implements InterfaceA<B> {
private final B b;
public AImplTwo(B b) {
this.b = b;
b.setA((A)this); // <-- Unchecked cast
}
}
And again, its clear to me, that the call b.setA((A)this) is an uncheck cast.
But how should this be implemented or redesigned in order to get rid of the unchecked code?

You are actually having a mutual recursive generic definition that you break by using raw types: in
b.setA((A)this); // <- Unchecked cast
this is of type InterfaceA<? extends InterfaceA.InterfaceB<? extends InterfaceA>>, but it should be of type InterfaceA<? extends InterfaceA.InterfaceB<? extends InterfaceA<? extends InterfaceA.InterfaceB<...>>>>. You would have to use instead
public interface InterfaceA<B extends InterfaceA.InterfaceB<?>> {
public interface InterfaceB<A extends InterfaceA<B>> { //<- cannot make a static reference to the non-static type B
void setA(A a);
}
}
but you cannot use B, which is non-static, in the static interface declaration (interface declarations are always static).
For detail, one further try: Using the alternative
public interface InterfaceA<B extends InterfaceA.InterfaceB<?>> {
public interface InterfaceB<A extends InterfaceA<? extends InterfaceA.InterfaceB<?>>> {
void setA(A a);
}
}
abstract class AImplTwo<B extends InterfaceA.InterfaceB<A>, A extends InterfaceA<B>> implements InterfaceA<B> {
private final B b;
public AImplTwo(B b) {
this.b = b;
b.setA((A)this); // <-- Unchecked cast
}
}
causes again an unchecked cast, since now the nested type parameter of InterfaceA in interface InterfaceB<A extends InterfaceA<? extends InterfaceA.InterfaceB<?>>> is again an arbitrary subclass of InterfaceA.InterfaceB<?>.
Update, since you've asked for a general design:
I would think of InterfaceB (in fact, interfaces in general) as abstraction from a concrete implementation: You only need the interface InterfaceB, not its implementation details, in your implementation of InterfaceA. Think of InterfaceB as a contract, and you do not care about the implementation. Hence there is no need for binding the implementation of InterfaceA to the implementation of InterfaceB:
public interface InterfaceA {
public interface InterfaceB {
void setA(InterfaceA a);
}
}
Only if, for reasons I can't see, you do want to have the same type for all instances of InterfaceB that you are using, you need generics. Vice versa for InterfaceA. With the last generics example above, you can at least fix the types for InterfaceA and InterfaceB, and would only have to dynamically assert that A's B and B's A are the same.
Showing that no type checked solution exists in Java is difficult, but maybe it becomes plausible with the following example, which would be a solution if Java allowed the combination of extends and super:
public interface A<TB extends A.B<?>> {
public interface B<TA extends A<? extends A.B<?>>> {
void setA(TA a);
}
}
class AImplTwo<TB extends A.B<TA>, TA extends AImplTwo<TB, TA> super AImplTwo<TB, TA>> implements A<TB> {
private final TB b;
public AImplTwo(TB b) {
this.b = b;
b.setA((TA)this);
}
}
...come to think of it, the Pluggable Type System, which adds further typing to Java, allows this combination of extends and super, and might therefore offer a solution to your problem. But I find it too complex for what you get, and would either stick with simply using Interfaces without generics or some unchecked cast.

Related

Restrict bounded type parameter A<B> and A<C>

I want to bind the type parameter of the child classes. Let's suppose these are the classes:
class A {}
class B extends A {}
class C extends A {}
I want to bind the above classes so if someone creating a class should only be able to pass self class name. Eg:
class B extends A<B> {} // valid
class C extends A<B> {} // invalid
class C extends A<C> {} // valid
The closest I could get to this is:
class A<T extends A<? super T>> {}
class B extends A<B> {}
class C extends A<B> {} // allows it, but I don't want to allow this.
How can this be achived?
Use case:
class A<T extends A<? super T>> {
private T t;
private A() {}
protected A(T t) {this.t = t;}
public T something() { return t; }
}
class B extends A<B> {
public B(B b) {super(b);}
public B anotherthing() { return this.something(); }
}
There's no way to do this at compile-time.
If you really want, you can enforce it at run-time (preventing problematic classes from being instantiated) by adding logic to A's non-private constructor:
protected A(T t) {
validateClass(getClass());
this.t = t;
}
private static void validateClass(final Class<?> clazz) {
final Type superclass = clazz.getGenericSuperclass();
if ((superclass instanceof ParameterizedType)
&& ((ParameterizedType)superclass).getRawType() == A.class
&& ((ParameterizedType)superclass)getActualTypeArguments()[0] == clazz
) {
// OK
} else {
throw new IllegalStateException(
clazz + " does not extend A<" + class.getName() + ">");
}
}
. . . but I don't think that's a great idea.
In general, although Java provides lots of features for compile-time protections, a Java program ultimately relies on developers to voluntarily write correct code. Many aspects of class contracts are documented, but not enforced. (For example, nothing forces the hashCode() and equals() methods to be consistent with each other; but if you're writing Java code, you'll read the documentation of those methods before overriding them, so will know what you need to do.) In your case, you're best off just telling developers that subclasses of A should pass themselves as the type argument to A, giving them an example, and trusting them to do it.

Call generic method with interface constraints on objects who may implement that interface

This is my code:
interface a {}
class b{}
class c extends b implements a{}
class d extends b{}
class e{
public void makeItWork(){
b[] bees = new b[] {new c(), new d()};
for (b bee: bees){
if (bee instanceof a) {
a beeA = (a) bee;
//how to call the method test if object bee conforms the the interface?
test(beeA.getClass(), beeA);
//this goes wrong
}
}
}
public <T extends a> void test(Class<T> classType, T concrete){
}
}
Besides maybe the bad design, I would like to know if it is possible to call the method test on objects who implements the interface a.
your test method doesn't need a generic type parameter.
You can define it as:
public void test(Class<? extends a> classType, a concrete) {
}
P.S. please use capitalized class names.
You can actually get away without using generics at all here:
public void test(a concrete) {
}

Subclasses with generics of subclasses

I have some issues with generics. I have a BaseObject with multiple sub-classes as well as a BaseContainer<T extends BaseObject> with sub-classes that correspond with BaseObject sub-classes.
public class TestClass extends BaseClass<BaseContainer<BaseObject>> {
// method signature tied to BaseClass generic
#Override
private BaseContainer<BaseObject> createContainer() {
BaseContainer<BaseObject> container;
// example logic here to determine which container to use
if (Math.random() < 0.5) {
container = new Parent1Container(); // incompatible types
} else {
container = new Parent2Container(); // incompatible types
}
return container;
}
abstract static class BaseObject {}
static class Parent1Object extends BaseObject {}
static class Parent2Object extends BaseObject {}
abstract static class BaseContainer<T extends BaseObject> {
public abstract void foo(T object);
}
static class Parent1Container extends BaseContainer<Parent1Object> {
public void foo(Parent1Object object) {}
}
static class Parent2Container extends BaseContainer<Parent2Object> {
public void foo(Parent2Object object) {}
}
}
public class BaseClass<T extends BaseContainer> {
public abstract T createContainer();
}
I have a method that returns BaseContainer<BaseObject>. Unfortunately, instantiating sub-classes of BaseContainer results in incompatible types error.
I have tried adding casts to the container instantiation, but it leaves ugly unchecked warnings that make me feel like I'm just missing something. I'd like to avoid those and suppress warnings.
If possible, how can I re-write the any of the classes to make the createContainer() method work?
As written here,
Neither List<Number> nor List<Integer> is a subtype of the other, even though Integer is a subtype of Number. So, any method that takes List<Number> as a parameter does not accept an argument of List<Integer>. If it did, it would be possible to insert a Number that is not an Integer into it, which violates type safety.
Since BaseClass is in a library and you cannot modify it, this case cannot be handled cleanly, i.e. as you expected.
Since Parent1Container and Parent2Container are not exactly BaseContainer<BaseObject> but BaseContainer<? extends BaseObject>
you need to change the signatures accordingly:
public class TestClass extends BaseClass<BaseContainer<? extends BaseObject>> {
...
public BaseContainer<? extends BaseObject> createConstructor() {
if (Math.random() < 0.5) {
return new Parent1Container();
} else {
return new Parent2Container();
}
}
...
}
BaseContainer<BaseObject> makes reference to all those BaseContainer (including extending classes) instances that are able to "handle" any BaseObject, where handle is a blanket-term for all the operations it may do with that type-argument.
In contrast BaseContainer<? extends BaseObject> refer to those BaseContainer instances that are meant to handle a subset of all BaseObject where the top parent class is unknown (thus the ?). It that ? happens to be BaseObject then these two sets would be equivalent.
If your case ? can be either Parent1Object or Parent2Object and so you cannot do better than just leave it as ?.

Guice, extending interfaces and constructor return type

Interface A and its implementation:
public interface A<K, E> {
public void foo();
}
public abstract class AImpl<K, E> implements A<K, E> {
public void foo(){};
}
Interface B, which extends interface A, and its implementation:
public interface B extends A<Integer, String> {
public void bar();
}
public class BImpl extends AImpl<Integer, String> implements B {
public void bar(){};
}
An abstract class C, which gets A injected:
public abstract class C<K, E> {
A<K, E> a;
#Inject
public setA(A<K, E> a){
this.a = a;
}
public A<K, E> getA(){
return a;
}
}
With Guice:
bind(new TypeLiteral<A<Integer, Book>>(){}).to(BImpl.class);
And the last class, which extends class C:
public class D extends C<Integer, String> {
public void fooBar(){
this.getA().bar(); //Gets BImpl injected by Guice, and call bar(): Not working - error
((B) this.getA()).bar(); //Working
}
}
Like you can see from inline comments, BImpl gets properly injected and can be used, if it has no additional methods, that extends A (interface B is empty). If I add any new method in B, I can't call it in D without it casting to B. My main goal is, giving a user possibility to extend A and use this functionality in D.
If I add any new method in B, I can't call it in D without it casting to B. My main goal is, giving a user possibility to extend A and use this functionality in D.
If the user needs the functionality provided by B but not A, they should declare that they need a B. Class D should declare what it needs - not rely on casting to make sure it was correctly configured beyond what was declared.

question about interfaces and generics in Java: type mismatch error

Suppose I have the following interface:
public interface Interface<T extends Number>{
public Vector<Interface<T>> getVector();
}
and the following class implementing that interface:
public abstract class C<T extends Number> implements Interface<T>{
private Vector<C<T>> vector;
public Vector<Interface<T>> getVector(){ //errror
return this.vector;
}
}
Why is not legal returning a Vector<C<T>> meanwhile is legal ( obviously) returning a Vector<Interface<T>>. C is actually implementing Interface, so it should be possible, right? What am I missing?
EDIT:
why this work for non generics interface? Is this actually a generic related problem?
public interface Interface{
public Interface getVector();
}
public abstract class C implements Interface {
private C;
public Interface getVector(){ //errror
return this.c;
}
}
Because the Vector is explicitly made up of Interface<T>, not things that extend Interface<T>, I believe this would work if you changed the definition to
public Vector<? extends Interface<T>> getVector();
The problem is that for some V implements T or V extends T that Foo<V> is not a supertype of Foo<T>. The compiler does not test inheritance on the generic arguments unless you explicitly indicate that extension point.
Using Vector<? extends Interface<T>> means "allow any class that implements or extends Interface<T>, whereas Vector<Interface<T>> means a vector consisting only of Interface<T> items.
Perhaps it's more concrete to consider that List<Integer> is not an acceptable replacement for List<Number> despite Integer extending Number for precisely the same reason.
update:
I tested this and the following compiles without any errors or warnings
interface Interface<T extends Number>{
public Vector<? extends Interface<T>> getVector();
}
abstract class C<T extends Number> implements Interface<T>{
private Vector<C<T>> vector;
public Vector<? extends Interface<T>> getVector(){
return this.vector;
}
}
It's the way generics work. They are not "covariant": if you have class AClass and its subclass SubAClass, Vector<SubAClass> is not a subclass of Vector<A>. (Note however that SubAClass[] is a subclass of AClass[].)
EDIT:
The seemingly obvious:
public ArrayList<Object> blah() {
return new ArrayList<String>();
}
won't compile because ArrayList<String> is not a subclass ArrayList<Object>. So in your case you can't return a Vector<C<T>> instance for a Vector<Interface<T>>.

Categories