Java generics with multiple enums implementing an interface - java

I want to pass a list of enum classes to a method, where all of the enums implement a common interface, and have the method return one of the enum values.
Looking at Java Generics Wildcarding With Multiple Classes, it seems that
public class Main
{
interface Foo {}
enum First implements Foo {
A, B, C;
}
enum Second implements Foo {
X, Y, Z;
}
interface Bar {}
enum Third implements Bar {
M, N, P;
}
enum Fourth implements Bar {
A, X, Z;
}
public static <I, T extends Enum<?> & I>
I enumVarArgs(Class<? extends T>... classes)
{
// Do stuff and return some instance of T
return null;
}
public static void main(String[] args) {
Foo foo = enumVarArgs(First.class,
Second.class);
Bar bar = enumVarArgs(Third.class,
Fourth.class);
}
}
should do what I want. However, this fails to compile under Java 10:
[ERROR] /me/test/src/main/java/test/Main.java:[17,42] error: unexpected type
required: class
found: type parameter I
where I,T are type-variables:
I extends Object declared in method <I,T>enumVarArgs(Class<? extends T>...)
T extends Enum<?>,I declared in method <I,T>enumVarArgs(Class<? extends T>...)
[INFO] 1 error
From the error message, I am guessing that Java wants me to do something like T extends Enum<?> & Serializable, where I pass an actual interface, rather than a type parameter. However, I need the API to be general so that I remains a generic parameter.
Is there a syntax that makes this work?
If it matters, we are using Java 10.

If interfaces are your design, then you can make the two interfaces extend a marker interface:
interface FooBar{}
interface Foo extends FooBar {}
interface Bar extends FooBar {}
And you can use this marker interface:
public static <T extends Enum<?> & FooBar>
FooBar enumVarArgs(Class<? extends T>... classes) {
return null;
}

I think what you need is:
interface OnlyImpelents<T> {}
interface Foo extends OnlyImpelents<Foo> {}
interface Bar extends OnlyImpelents<Bar> {}
static <T extends Enum<?> & OnlyImpelents<? super T>> T enumVarArgs(T... values) {
return values[0];
}
public static void main(String[] args) {
Foo foo = enumVarArgs(First.A, Second.X);
}
The marker interface OnlyImpelents<T> prevents any class from implementing both Foo and Bar
The only way to get enum values from a enum class is via reflection, which doesn't need to have a static type. Personally I think this is not a good object-oriented design, using T... as args should be better

Related

Java Incompatible equality constraint in list

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.

Java Generics & operator

I am facing some difficulty to understand an expression in java generics.
Please help on this:
public interface Inter {
<T extends Enum<T> & FunctionalInterface> String getString();
}
The code you have given is legal, but useless.
It is useless for two reasons:
You have defined a generic type, T, as part of the method declaration that must implement the Enum<T> interface as well as the FunctionalInterface interface. However you haven't then used that type anywhere in the method's signature (i.e. arguments or return type) so it is effectively ignored.
Having an interface implement 'FunctionalInterface' is possible, but certainly not it's intended use. It is designed to be an annotation to an interface, not an interface itself.
You could make this combination work:
public interface Inter {
<T extends Enum<T> & FunctionalInterface> String getString(T value);
}
static class InterImpl implements Inter {
#Override
public <T extends Enum<T> & FunctionalInterface> String getString(T value) {
return value.name();
}
}
enum EnumImpl implements FunctionalInterface {
A, B, C;
#Override
public Class<? extends Annotation> annotationType() {
return null;
}
}
public static void main(String[] args) {
InterImpl impl = new InterImpl();
System.out.println(impl.getString(EnumImpl.B));
}
You'll see that the EnumImpl enumeration implemements Enum and FunctionalInterface so it can be used as an argument to getString.
So that's an explanation but, frankly, I can't think of any useful use case for such a piece of code.

Using Java generics while inheriting from an abstract class

I want to extends a generic typ from an abstract class:
abstract class Foo {
public void doStuff() {}
}
public class Bar<T extends Foo> {
public void doFooBar(Foo param) {
/* Code here */
param.doStuff();
}
}
In other words: A class Bar should created with an generic type, which extends from Foo. Bar should be able to have methods, where Foo is an parameter (because the generic type extends from Foo, so it should be possible).
Using instead of Foo a predefined class like String oder BigDecimal, it works so far. But in my case, Bar complains about not finding class Foo.
I'm using Eclipse.
Did I miss something?
SOLUTION:
Foo has to be a public modifier, than it works. I expected, that abstract class are public by default (like Interfaces). Eclipse doesn't complain about the missing modifier.
abstract class Foo() {
...
is a syntax error.
Correcting that to
abstract class Foo {
...
results in no compilation errors. Also, note that it should probably be
public class Bar<T extends Foo> {
public void doFooBar(T param) {
// ----------------------^
// Type parameter here
/* Code here */
}
}
Remove the () parantheses after classname Foo
Here is modified code:
abstract class Foo {
public void doStuff() {}
}

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.

Why is a generic argument that "extends" something not allowed in derived function, but generic return type is?

I would like to override a generic function in a subclass, as follows:
Superclass:
public abstract class Metric {
public abstract <T extends Foo> T precompute(); // valid syntax
public abstract <T extends Foo> void distance(T arg); // valid syntax
public static class Foo {}
}
Subclass:
public class MetricDefault extends Metric {
#Override
public Bar precompute() { return new Bar(); } // Valid - return type extends Foo
#Override
public void distance(Bar arg) {} // Invalid ??? - argument type extends foo
public static class Bar extends Metric.Foo {}
}
The generic function, when the generic type is the return value of the function, is valid Java code and builds successfully.
Changing only the placement of the generic type - making it the argument to the function, rather than the return type - and it becomes invalid Java code.
Why is the latter case invalid? What can I do to implement this functionality?
The method declaration
public abstract <T extends Foo> void distance(T arg);
means that the method takes an T argument, and the caller can decide which subtype of Foo to use as T.
The method declaration
public abstract <T extends Foo> T precompute();
means that the method returns some object of type T, and the caller can decide which subtype of Foo to use as T.
This last method can't really be implemented (apart from returning null), since your method does not really know what an object to produce here.
In your concrete class you try to override the methods - for my understanding you shouldn't be allowed for both of them, but maybe the compiler is a bit more relaxed than me.
I think what you really want is something like what Overbose posted.
public abstract class Metric<T extends Foo> {
public abstract T precompute(); // valid syntax
public abstract void distance(T arg); // valid syntax
public class Foo {}
}
then if as I understood Bar extends Foo:
public class MetricDefault extends Metric<Bar> {
#Override
public Bar precompute() { return new Bar(); }
#Override
public void distance(Bar arg){}
public class Bar extends Foo {}
}
Because the signature of distance(T) in the superclass specifies that someone that has a reference to a Metric should be allowed to pass any type that extends Foo as an argument.
The first method works fine because anyone referring to Metric is already prepared to handle the return type of Bar, since the signature refers to a parent type of Bar.
For this to work, you need to make T a parameter of the type, rather than of the methods.
The way you are attempting to do it, your new method does not override the abstract base method. After type erasure is performed, it amounts to the following code:
public abstract class Metric {
public abstract Foo precompute(); // valid syntax
public abstract void distance(Foo arg); // valid syntax
public class Foo {}
}
public class MetricDefault extends Metric {
public Bar precompute() { return new Bar(); } // Valid - return type extends Foo
public void distance(Bar arg) {} // Signature not compatible - does not override distance(Foo)
public class Bar extends Foo {}
}
As #PaĆ­lo Ebermann mentioned, the following overriding should not be legal
<T extends Foo>
T precompute();
Bar precompute()
Rules in JLSv3 #8.4.8.3 and #8.4.5 forbid this overriding. Javac should have reported error on it.
There are 2 possible explanations
the spec omitted an intuitive&obvious rule: the "is return-type-substitutable" relation should be transitive. T->Foo->Bar, Bar overriding T is legal.
javac is buggy. It somehow mistakes Foo as the return type of method#1 when validating the overriding.
The 1st explanation is quite implausible. If the (nastily defined) relation is transitive, it's too hard to check if it holds for 2 arbitrary types. So the 2nd explanation is probably truer.

Categories