Java Incompatible equality constraint in list - java

I have a multi level class structure and want to pass their implementation to a function that can call functions on them, but I get an Incompatible equality constraint: Test.SubDTO2 and Test.SubDTO error.
Here is the code:
public class Test {
abstract class DTO { }
class SubDTO extends DTO implements Interf{ }
class SubDTO2 extends DTO implements Interf{ }
class DAO<T extends DTO> { }
interface Interf { }
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2)); // <- error is in this line
}
static <T extends DTO & Interf> void func(List<DAO<T>> arg) {
}
}
A more detailed example on what I try to achieve:
public class Test {
abstract class DTO {
abstract void func1();
}
class SubDTO extends DTO implements Interf{
#Override
public void func2() {
// comes from Interf
}
#Override
public void func1() {
// comes from DTO
}
}
class SubDTO2 extends DTO implements Interf{
#Override
public void func2() {
// comes from Interf
}
#Override
public void func1() {
// comes from DTO
}
}
class DAO<T extends DTO> {
public T dto() {
return null;
}
}
interface Interf {
void func2();
}
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2));
}
static <T extends DTO & Interf> void func(List<? extends DAO<? extends DTO>> arg) {
arg.get(0).dto().func1(); // <- I can't call func2() here
}
}
exact error message:
[ERROR] required: java.util.List<Test.DAO<T>>
[ERROR] found: java.util.List<Test.DAO<? extends Test.DTO>>
[ERROR] reason: inference variable T has incompatible equality constraints Test.SubDTO2,Test.SubDTO
I need the list in the function func to extend DTO and also implement Interf as well, because I call certain functions on them.
Why is this happening? It works fine if I change the signature of the func and pass only one DAO, but I need it to work with multiple.
What are my options here?
I tried it with multiple java versions (1.8+), all the same.

Your function should be declared like this:
static <T extends DTO & Interf> void func(List<DAO<? extends T>> arg) {
Notice that I changed List<DAO<T>> to List<DAO<? extends T>>. This is because the expression Arrays.asList(daoImpl1, daoImpl2) produces a value of type
List<DAO<? extends DTO & Interf>>
(Of course, this isn't real syntax for a type in Java. There's no syntax for intersection types in Java but Java does know about them when doing type inference, and you could have these types in your code if you use var. I use this notation here just for illustrative purposes.)
If you know PECS, you'll know that this is a list of DAOs that produces DTO & Interfs/Ts, but does not consume DTO & Interfs/Ts. If you are lost at this point, please go read the PECS post - it's great. See also: Difference between <? super T> and <? extends T> in Java
The reason why it does this is quite intuitive. Imagine if DAO is just a container for a T.
static class DAO<T extends DTO> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
If Arrays.asList(daoImpl1, daoImpl2) had produced a list of DAO<DTO & Interf> (with no extends or super), you'd be able to call getT and setT on elements of the list! And being able to call setT is especially dangerous you see - you'd be able to do this:
// suppose arg is a List<DAO<DTO & Interf>>
arg.get(someRandomNumber).setT(new SubDTO());
What if someRandomNumber happens to be 1, and we get the second element, which is a DAO<SubDTO2>? Putting a SubDTO inside that destroys the whole type-safety of generics.
The only type-safe thing to do on elements of such a list like [daoImpl1, daoImpl2] is to use them as producers of DTO & Interfs, hence the type is marked ? extends DTO & Interf. This means that if you have any methods on DAO that takes in a T, you won't be able to call them on elements of this list*.
Also note that, just in case I was not clear, it is not the list that is only a producer - the list is both a producer and consumer of DAOs. It's just that the DAOs in the list are producers of their Ts.
* except by passing nulls.

Related

How can you bind the type of a generic interface to another generic interface?

I am trying to write an interface that has bounds on multiple layers. As an example, consider the following code:
// the bound type on U is unexpected and doesn't compile
public interface CollectionNumberWrapper<T extends Collection<U extends Number>> {
void setData(T data);
U sumOfAllNumbersInCollection()
};
public class NumberCollection implements List<AtomicInteger>{
///...implement...
};
public class StringCollection implements Collection<String>{
///...implement...
};
//This should be legal
public class NumberCollectionWrapper implements CollectionNumberWrapper<NumberCollection>{
#Override
void setData(NumberCollection data){
//...
};
#Override
AtomicInteger sumOfAllNumbersInCollection(){
//...
}
}
//This should not be legal, the type parameter should be out of bounds
public class StringCollectionWrapper implements CollectionNumberWrapper<StringCollection>{
}
Is it possible to be this specific with type bounds in Java?
You can, but it'll take a little more work: you must write
public interface CollectionNumberWrapper<U extends Number, T extends Collection<U>> { ... }
...though for this specific use case, I would omit T entirely and simply use Collection<U> everywhere.

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 ?.

Restrict generic types in java based on implementation of generic interface

So I have got 2 generic interfaces.
First interface is implemented like this.
public interface First<E>
{
void method(E e)
}
public class FirstImpl implements First<String>
{
void method(String s) { System.out.println(s); }
}
public class FirstImpl2 implements First<Double>
{
void method(Double d) { System.out.println(d); }
}
I need the second interface's (second interface is shown below) generic type to allow only the classes that are used when implementing the first interface, in our case String and Double. Is there any clean way to do this, something like
public interface Second <E, ? extends First<E>>
{
void method(E e);
}
public class SecondImpl <E> implements Second <E, ? extends First<E>>
{
void method(E e) { System.out.println(e); }
}
, so the in Second's generic E would fit only String and Double and all classes that are used to implement First<E>?
Nope. You can not restrict the generic type of the Second in that sense. You can still provide an another type information independently. Say,
class XYZ implements First<Bar> { ... }
an another class may provide an another type information for the Second, like
class ZYX implements Second<Foo, SomeOtherType<Foo>> { ... }
assuming SomeOtherType implements/extends whatever from type First. If you want to bind those two interfaces on their generic type, you can use inheritance between the implementations:
interface First<T> {}
interface Second<T> {}
class Foo<E extends T> implements First<T> {}
class Bar<E extends T> extends Foo<E> implements Second<E> {}
Now, the type E, is associated with the type T, via E extends T.

Why doesn't this generic method accept any type?

In the code below, when I call getList() I am not able to specify <T>. getList<T>() does not compile.
Instead, I may only call getList() - but then <T> is always simply <Event> .
Why is this?
class Foo
{
public static void main (String[] args) throws java.lang.Exception
{
// For the sake of a complete example - the next method has
// my question.
Foo f = new Foo();
f.register(new Subscriber<MyEvent>() {
public void handle(MyEvent event){};
});
}
public <T extends Event> void register(Subscriber<T> subscriber) {
// Below won't work. I can't specify <T>, so getList()
// will return a HashSet<Subscriber<Event>>, to which I cannot
// add the Subscriber<T>!
getList().add(subscriber);
// Why can't I call getList<T>().add(subscriber) ?
}
private <T extends Event> HashSet<Subscriber<T>> getList() {
// For the sake of example, simply return a new HashSet.
return new HashSet<Subscriber<T>>();
}
}
interface Subscriber<T extends Event> {
public void handle(T event);
}
interface Event { }
class MyEvent implements Event { }
It appears that Java won't accept a <T> as the type argument to a simple name such as getList(). But it will accept it if you explicitly state this. when calling the method:
this.<T>getList().add(subscriber);
I believe the right answer is to make Foo into Foo<T extends Event> so that when in Foo T is defined.
Otherwise, try this.<T>getList(). This is how this is done for statics MyClass.<String>someMethod(). Not sure if it will also work for an instance method. Again, the best answer is to make Foo generic.
The T from you example is extending Event in both methods of Foo class. Well that implicitly means you Foo class is working only with <T extends Event> type inference. Unfortunately, your T is defined only at method scope. For humans all looks alright. But compiler is a bit different. Compiler doesn't believe you and it's not able to figure out implicit informations, however they are just fine, logically. You did not define your T at Class scope and the compiler did not figure out you are using the same type inference in both methods. So, compiler wont let you mix these method together.
So, the solution should explicitly define type inference is for Class scope use not only for method scope.
class Foo<T extends Event>
{
public static void main (String[] args) throws java.lang.Exception
{
// For the sake of a complete example - the next method has
// my question.
Foo<MyEvent> f = new Foo<MyEvent>();
f.register(new Subscriber<MyEvent>() {
public void handle(MyEvent event){};
});
}
public void register(Subscriber<T> subscriber) {
// Below won't work. I can't specify <T>, so getList()
// will return a HashSet<Subscriber<Event>>, to which I cannot
// add the Subscriber<T>!
getList().add(subscriber);
// Why can't I call getList<T>().add(subscriber) ?
}
private HashSet<Subscriber<T>> getList() {
// For the sake of example, simply return a new HashSet.
return new HashSet<Subscriber<T>>();
}
}
interface Subscriber<T extends Event> {
public void handle(T event);
}
class MyEvent extends Event {
}
class Event {
}
Perhaps you need to be a little more gentle with Java. This seems to work without warnings:
HashSet<Subscriber<T>> list = getList();
list.add(subscriber);

java Generic Type vs Abstract class for parameter

I'm studying Java Generic type.
I have the abstract class AbstractInputdata.
public abstract class AbstractInputData {
....
}
Some class that extend AbstractInputData
public class Email extends AbstractInputData{
...
}
public class Mobile extends AbstractInputData{
...
}
......
A.
public class ProcessorA {
public static boolean isCustomData(AbstractInputData abstractInputData) {
....
}
}
B.
public class ProcessorB {
public static <T extends AbstractInputData> boolean isCustomData(T t) {
...
}
}
Is there any difference between A and B?
The only difference is that the second method with appear as a generic typed method via Reflections. It's behaviour will be the same except in odd cases like this
processorB.<MyType>isCustomData(t); // won't compile unless t is a MyType
You would have to tell it what type you expect it to match, which isn't that useful IMHO.
Since your methods only produce a boolean, there is no difference. But in case you want to return the input you can use B to preserve the generic type:
public class ProcessorB {
public static <T extends AbstractInputData> boolean isCustomData(T t) {
...
}
public static <T extends AbstractInputData> T copyCustomData(T t) {
...
}
}
ProcessorA could only return an object of type AbstractInputData while processorB returns Email or Mobile depending on the parameter type.

Categories