Relation between generics type in Java - java

Please, consider my code:
interface AInterface {}
interface BInterface extends AInterface {}
class AClass implements AInterface { }
class BClass extends AClass implements BInterface {}
class Descriptor<S extends AClass, T extends AInterface> {
private Class<S> classClass;
private Class<T> interfaceClass;
public Descriptor(Class<S> classClass, Class<T> interfaceClass) {
this.classClass = classClass;
this.interfaceClass = interfaceClass;
}
}
class Foo {
public void test() {
Descriptor<AClass, BInterface> descriptor =
new Descriptor<>(AClass.class, BInterface.class);//LINE X
}
}
So, I have two interfaces and two classes that implement them. And I have a descriptor to which I must add two classes - the class of the interface and class of the implementation. The question is how to add relation restrict between them. I mean, that at LINE X I must get compilation error, because AClass doesn't implement BInterface. How to do it?

I do not think this is possible. Enforcing multiple type bounds is possible when all of them but the first one (optionally) are interfaces, but I'm unaware of any trick allowing to do it for multiple classes. Here's how it works for interfaces:
public class Bar {}
public class Baz extends Bar {}
public class Foo1<T extends Bar & Serializable> {} // compiles
public class Foo2<T extends Serializable & Bar> {} // doesn't compile
public class Foo2<T extends Bar & Baz> {} // doesn't compile
public class Foo3<T extends Serializable & Closeable> {} // compiles
public class Foo4<T extends Serializable & Closeable & Runnable> {} // compiles
What's your real use case? Perhaps there's a way to approach the problem differently.

Related

How to make method generic when using inheritance in Java?

I have class Employee and 3 classes that extends Employee class.
I also have EmployeeService interface where i want to have only one save method to handle saving each type of Employee. So i assumed that it could be solved using generics.
This is what i tried in EmployeeService interface:
public interface EmployeeService {
<SubRequestT extends Employee>EmployeeResponse save(SubRequestT requestT);
}
And class that provide implementation:
#Service
public class EmployeeServiceImpl implements EmployeeService {
// So here in argument i want to have to put any kind of Employee, for example:
#Override
public EmployeeResponse save(OfficeEmployee requestT) {
// Logic for saving employee
return null;
}
}
But when i changed from Employee type to any other, for example OfficeEmployee who is extending from Employee, complier is giving me an error. What is best way to solve this?
With "method generics" I (me & compiler) also struggle, but with "type generics" we can do that!
Assuming:
class Foo {/*...*/}
class Bar extends Foo {}
class Baz extends Foo {}
// extending your question to two generic parameters:
class FooResult {}
class BarResult extends FooResult {}
class BazResult extends FooResult {}
When we define our interface like:
interface FooI<I extends Foo, R extends FooResult> { //or with even more (fixed size) "generic parameters"
R save(I request);
}
We can override it like:
class BarImpl implements FooI<Bar, BarResult> {
#Override
public BarResult save(Bar bar) {
// ...
return ...;
}
}
class BazImpl implements FooI<Baz, BazResult> {
#Override
public BazResult save(Baz baz) {
// ...
return ...;
}
}

Generic type parameter which implements generic interace

In a Java application, I'd like to use a generic type parameter which implements an interface which uses a generic parameter itself.
public interface SuperInterface<T> { ... }
public interface MyInterface extends SuperInterface<MyClass> { ... }
public class Worker<T extends SuperInterface<U>> extends SuperWorker<String, Boolean> {
}
However, the class declaration won't work like that. T should be of type MyInterface (or any other interface which implements the SuperInterface) and U should be of type MyClass (or any other class according to the interface).
You have to declare all of the type parameters at the top level. It's annoying, but that's how it is.
public class Worker<U extends MyClass, T extends SuperInterface<U>> { ...
The order of the parameters doesn't matter; you can also do Worker<T extends..., U extends...>. All that matters is that each is declared at the top level of the nested generics.
Here's a complete class:
public class MyClass {
public interface SuperInterface<T>{}
public interface MyInterface extends SuperInterface<MyClass> {}
public class Worker<U extends MyClass, T extends SuperInterface<U>> {}
public void compileTest() {
// just to make sure the declaration compiles
Worker<MyClass, MyInterface> worker = null;
}
}

BaseFoo cannot be inherited with different arguments: <T,X.Bar<T>> and <T,X.Foo<T>>

This is a simplified version of Java inherited Fluent method return type in multiple level hierarchies.
Given the following code:
public enum X {
;
static interface BaseFoo<T, S extends BaseFoo<T, S>> {
S foo();
}
static interface Foo<T> extends BaseFoo<T, Foo<T>> {
void foo1();
}
static interface BaseBar<T, S extends BaseBar<T, S>> extends BaseFoo<T, S> {
S bar();
}
static interface Bar<T> extends BaseBar<T, Bar<T>>, Foo<T> {
void bar1();
}
}
run javac X.java I get the error message:
X.java:15: error: BaseFoo cannot be inherited with different arguments: <T,X.Bar<T>> and <T,X.Foo<T>>
static interface Bar<T> extends BaseBar<T, Bar<T>>, Foo<T> {
^
Anyone has any solution?
Disclaim: I am trying to use the pattern to implement the fluent interface across a container class inheritance hierarchy.
Background: to make it easier for people to understand why I need this, here is the story. I want to create a container family: Traversal <- Sequence <- List. So Traversal has a method Traveral<T> accept(Visitor<T>) (no PECS for short), this method should always return this after iterating the visitor through the elements. When I have a List type, I want the method return List<T> instead of Traversal<T> because I want to make it possible to call something like myList.accept(v).head(15), where head(int) is a method of List not Traversal
A class or interface cannot implement or extend from different instantiation of a generic interface. Your Bar interface is breaking this rule. Let's examine the interface declaration:
static interface Bar<T> extends BaseBar<T, Bar<T>>, Foo<T>
So, Bar<T> extends two interfaces:
BaseBar<T, Bar<T>>
Foo<T>
In addition to that, those two interfaces extend from different instantiation of the same interface BaseFoo.
BaseBar<T, S extends BaseBar<T, S>> extends BaseFoo<T, S>
Foo<T> extends BaseFoo<T, Foo<T>>
Those inherited interfaces are eventually also the super interfaces of Bar interface. Thus your Bar interface tries to extend from 2 different instantiation of BaseFoo, which is illegal. Let's understand the reason using a simple example:
// Suppose this was allowed
class Demo implements Comparable<Demo> , Comparable<String> {
public int compareTo(Demo arg) { ... }
public int compareTo(String arg) { ... }
}
then after type erasure, compiler would generate 2 bridge methods, for both the generic method. The class is translated to:
class Demo implements Comparable<Demo> , Comparable<String> {
public int compareTo(Demo arg) { ... }
public int compareTo(String arg) { ... }
// Bridge method added by compiler
public int compareTo(Object arg) { ... }
public int compareTo(Object arg) { ... }
}
So, that results in creation of duplicates bridge method in the class. That is why it is not allowed.

Enforcing parameter types on dependent interfaces?

These interfaces are very simple:
public interface Thawed<F>
{
F freeze();
}
public interface Frozen<T>
{
T thaw();
}
This works, no problem.
But now, how would I require F in Thawed to implement Frozen, and T in Frozen to implement Thawed?
The closest I could get is:
public interface Thawed<F extends Frozen<? extends Thawed<F>>>
public interface Frozen<T extends Thawed<? extends Frozen<T>>>
But that sounds quite recursive... (also works with Thawed<?> and Frozen<?>)
I think this should work:
public interface Thawed<F extends Frozen<?>> { ... }
public interface Frozen<T extends Thawed<?>> { ... }
I don't think you need anything deeper than that, since all you need to do is specify that F is some kind of Frozen (and similarly for T).
The closest I could get is
That is the correct answer; you cannot get better than that within the Java type system.
Note that this does allow
class Cat implements Thawed<Dog> { }
class HouseCat extends Cat { }
class Dog implements Frozen<HouseCat> { }
You could prevent that by using two generic parameters:
public interface Thawed<F extends Frozen<T, F>, T extends Thawed<F, T>> { }
public interface Frozen<T extends Thawed<F, T>, F extends Frozen<T, F>> { }
However, I think this is too confusing to be useful.
It would also still allow
class Cat implements Thawed<Dog, HouseCat> { }
class HouseCat extends Cat { }
class Dog implements Frozen<HouseCat, Dog> { }

need trick with object creator

This is my code:
public interface InterfaceA<J>{
// …
}
public interface InterfaceB extends InterfaceA<String> {
// …
}
public interface InterfaceC extends InterfaceA<Long>{
// …
}
public class Creator<J, I extends InterfaceA<J>> {}
public abstract class Base<J, J1> implements InterfaceA<J> {
protected Creator<J, J1> creator;
protected Base() {
creator=ObjectCreator.createCreator();
}
}
public class Extension1 extends Base<Integer> implements InterfaceB {
// …
}
public class Extension2 extends Base<Double> implements InterfaceC {
// …
}
I want Extension1 to have Creator<Integer, InterfaceB> and Extension2 to have Creator<Double, interfaceC>. See the pattern? Creator<T1, T2> where T1 is the type of immediate parent and T2 is the interface implemented by said class. Is there any way to do this? can anybody tell the code of ObjectCreator.createCreator()?
Right now my code looks like this:
public class ObjectCreator {
public static <J, I extends InterfaceA<J>> Creator<J, I> createCreator() {
return new Creator();
}
}
I got errors all over my code. I'm really confused. What am I missing here?
There's a whole bunch of stuff you missed, a compiling version would look something like this:
package scratch;
interface InterfaceA<J> {
// …
}
interface InterfaceB extends InterfaceA<String> {
// …
}
interface InterfaceC extends InterfaceA<Long> {
// …
}
class Creator<J, I extends InterfaceA<J>> {
}
abstract class Base<J, I extends InterfaceA<J>> {
protected Creator<J, I> creator;
protected Base(Class<J> jClass, Class<I> iClass) {
creator = ObjectCreator.createCreator(jClass, iClass);
}
}
class Extension1 extends Base<String, InterfaceB> implements InterfaceB {
protected Extension1() {
super(String.class, InterfaceB.class);
}
}
class Extension2 extends Base<Long, InterfaceC> implements InterfaceC {
protected Extension2() {
super(Long.class, InterfaceC.class);
}
}
class ObjectCreator {
public static <J, I extends InterfaceA<J>> Creator<J, I>
createCreator(Class<J> jClass, Class<I> iClass) {
return new Creator();
}
}
In no particular order of importance:
When you have a class with a signature like createCreator() has, you need to pass Class objects as type tokens to it. The Java compiler can't infer the types based on the type of the variable you're assigning the return value to. Besides, you want them there anyway because of type erasure, otherwise you couldn't specialise the Creator based on the given types.
If you have Base<J, I> with two type parameters, extending classes should use both of those type parameters.
Your extension class signatures were odd. You can't have class Extension1 extends Base<Integer, InterfaceA<String>>, because you can't have a Creator<Integer, InterfaceA<String>>. Using explicit type tokens in createCreator() would have forced you to propagate this constraint everywhere it needs to be and made the error less mysterious. You can't really make Base independent of the constraint between the J and I type parameters.

Categories