EnumSet as a parameter in generic Interface - java

I've a use case :
inteface A{
get(EnumSet<?> fetchModes);
}
class B implements A{
//Here FetchMode is an enum
get(EnumSet<FetchMode> fetchMode){
//Some logic here
}
}
But it's throwing compile time error :
Method get of class B has the same erasure as get(EnumSet fetchMode) of type A but doesn't override it.
I had read that Enums cannot be generic but is there any way to implement this usecase ?
(Basically want the EnumSet to be generic and different implementations can pass different Enums)

A method can override another if the argument types match exactly, but yours doesn't. Eventhough EnumSet<FetchMode> is a subtype of EnumSet<?>, they are not exactly the same. You are not overriding the super class method get(EnumSet<?> fetchModes); in your subclass, rather you are overloading it with a different parameter type. Both of these has the same signature due to erasure when you inspect or decompile the bytecode which is get(EnumSet fetchModes) and your compiler starts complaining.
This is covered in JLS ยง8.4.8.1:
A class cannot have two member methods with the same name and type
erasure
A naive attempt at fixing the problem is to change the parameter type such that it is compatible with that of the super class, overriding the method properly in your sub class.
#Override
public void get(EnumSet<?> fetchModes) {
}
Though this fixes the compiler error after a fashion, it is still not elegant since it allows your EnumSet to store any Object. But ideally you may want it to store only some subtype of Enum. This idiom supports that.
What you have to do is declare a generic interface with bounded type parameter and then implement it by overriding the method properly as shown below.
public interface A<E extends Enum<E>> {
void get(EnumSet<E> fetchModes);
}
public class B implements A<FetchMode> {
#Override
public void get(EnumSet<FetchMode> fetchModes) {
}
}

try this you have to make the generic type extends Enum:
public class B implements A<FetchMode> {
//Here FetchMode is an enum
public void get(EnumSet<FetchMode> fetchMode){
//Some logic here
}
}
}
interface A<T extends Enum<T>> {
void get(EnumSet<T> fetchModes);
}

Related

Cannot override method that takes in parameter of inner class of generic

Ok, I'll try to explain this as cleanly as I can.
I've created a generic abstract controller class that has a method hasCreatePermissions that looks something like this:
public abstract class ApplicationController<
AppEntity extends ApplicationEntity,
AppService extends ApplicationService<AppEntity>,
DTOManager extends ApplicationDTOManager
> {
// Other methods, properties, etc...
public boolean hasCreatePermissions(DTOManager.CreationRequest requestBody, Optional<UUID> requestingUser) {
return false;
}
}
Essentially, I want any class that overrides this method to be able to use its own DTOManager class as the parameter when it overrides this method.
The generic ApplicationDTOManager class looks like
public abstract class ApplicationDTOManager {
public abstract class CreationRequest {}
public abstract class CreationResponse {}
}
and any class that inherits ApplicationDTOManager can add classes that extend CreationRequest and CreationResponse for their own implementation of respective DTOs.
However, lets say I try to extend it with a UserResource class (assume UserDTOManager exists with an implementation for CreationRequest):
#RestController
public class UserResource extends ApplicationController<
User,
UserService<User>,
UserDTOManager
> {
#Override
public boolean hasCreatePermissions(UserDTOManager.CreationRequest requestBody, Optional<UUID> requestingUser) {
// Stuff
}
}
I'm told that this does not override any super class methods. Why? Is there any way to achieve this as I did not want to pass too many generics to my ApplicationController class, but also cannot have a constructor.
class ApplicationController<
AppEntity extends ApplicationEntity,
No, stop right there. This is declaring a type variable with the bound rules: "Must be either ApplicationEntity or any subtype thereof" and you named it AppEntity. This is going to make your head go in circles when you read the code later, 'I keep confusing reified types with type variables' comprises 95% of all confusion about generics. I know it seems unreadable, but there really is just only one way to go about it, and that is to use single capital letters for all your type vars. So let's fix that right now:
public abstract class ApplicationController<
E extends ApplicationEntity,
S extends ApplicationService<E>,
M extends ApplicationDTOManager> {
Which then immediately lets us see a big problem in the next line:
public boolean hasCreatePermissions(M.CreationRequest requestBody) {}
Of course that can't work. M is a type variable, at compile time the compiler has no idea what type it is. It could be bound to some type that doesn't even exist yet right now. You can't ask for a reified inner type on a type variable. You can of course simply talk about ApplicationDTOManager.CreationRequest and that's presumably what you want.
Alternatively, you're thinking that subtypes of ApplicationDTOManager may also want to subclass ApplicationDTOManager.CreationRequest. This is possible, but then all ApplicationDTOManager types need to carry their associated CreationRequest type as a type variable. We thus fix a few things:
public class ApplicationDTOManager<R extends ApplicationDTOManager.CreationRequest> {
public static class CreationRequest {}
}
You may have a non-static inner class named CreationRequest. I'm going to stop you again on that - non-static inners have an invisible inner field of their outer's type, and combining that invisible voodoo magic with generics just doesn't work. Don't do it. You can explicitly make that field if you must have it, and make a constructor that takes it. This is what javac generates for you if you don't add static to your inner classes. But by making it explicit, you take control of the generics, which you have to here, and avoid confusion which given the nature of the question seems pertinent.
I'm told that this does not override any super class methods. Why?
Java's method names include all their erased types. The name of this method:
class List<T extends Number> {
int hello(String name, boolean[] hi, T arg) throws SQLException {}
}
is, as far as the JVM is concerned, hello(Ljava/lang/String;[ZLjava/lang/Number;)I.
Yeah, no, really. javap -c -v a class file and you'll see it. (I is integer, [ is array, Z is boolean, and Ltxt; encodes ref type names in JVM style, e.g. with slashes and dollars instead of dots). It's written name(params)ret.
If you then subtype something and introduce a method whose erased JVM name is identical, you're overriding. If you don't, it is not an override. Merely an overload. Overrides are dynamically dispatched. But overloads are not - The names are all linked up at compile time. However, for any given 'JVM method name', the lookup is done dynamically based on the receiver type. In other words:
class Fruit {
void hi(Fruit f) { System.out.println("Fruit Fruit"); }
void hi(Apple a) { System.out.println("Fruit Apple"); }
}
class Apple extends Fruit {
void hi(Fruit f) { System.out.println("Apple Fruit"); }
void hi(Apple a) { System.out.println("Apple Apple"); }
}
Fruit f = new Fruit();
Fruit a = new Apple();
a.hi(a);
Will print Apple Fruit. You'd think it should print Apple Apple perhaps - we are calling apple's hi passing an apple, no? But the invocation a.hi(a) is invoking the method named hi(Lfruit;)V (because the type of a is Fruit). The receiver variable (a) has compile time type Fruit, but its real type is Apple. So, which of the hi(Lfruit;)V methods is chosen is done with dynamic dispatch - you get apple's hi(Fruit). Deciding between going with hi(Fruit) and hi(Apple) is done by the compiler only. Given that the type of the expression a is Fruit, you get hi(Fruit). The fact that if you resolve this expression, you get an object whose .getClass() returns Apple.class, doesn't change this.
Hence, what you wrote, does not override. Different name, even if you erase.
Toss generics in the mix and it gets funky. But you can do this.
public abstract class ApplicationDTOManager<I extends CreationRequest, O extends CreationResponse> {
public abstract static class CreationRequest {}
public abstract static class CreationResponse {}
}
public abstract class ApplicationController<
E extends ApplicationEntity,
S extends ApplicationService<AppEntity>,
I extends CreationRequest,
O extends CreationResponse,
M extends ApplicationDTOManager<I, O>
>
// heck that's probably too many, at some point generics aren't worth it
{
public abstract boolean hasCreatePermissions(I requestBody);
}
#RestController
public class UserResource extends ApplicationController<
User,
// UserService<User>, // this seems wrong!
UserService, // UserService should extends ApplicationService<User>
UserDTOManager.CreationRequest,
UserDTOManager.CreationResponse,
UserDTOManager> {
#Override
public boolean hasCreatePermissions(UserDTOManager.CreationRequest requestBody, Optional<UUID> requestingUser) {
// Stuff
}
}
Not sure all this is worth the pain, but, if you insist on linking all this together with generics, the above is the only way. You cannot express the notion 'has an inner type that is a subtype of CreationRequest' is a generics bound.
If you override a method you cannot have a different signature, If the method you override requires a DTOManager.CreateRequest you cannot use a child class within the override method.
You have to "support" all types of input that the parent method could take.
I believe that you need this because the permission validation relies on methods or fields of the child class. If so you should implement it inside the child class.

Override a method in Java by providing a Subtype as a Parameter

I want to override a method in Java by passing a concrete subtype of the parameter type that is specified in the super class. See the following example. Is there a way to get this working in Java?
interface A {
<T> T f(V<T> v);
}
interface V<T> {
T v();
}
class B implements A {
#Override // Here it gives error: Method does not override method from its superclass
public <T> T f(V1<T> v) {
return v.v1();
}
}
interface V1<T> extends V<T> {
T v1();
}
I have also tried this version for A but doesn't work:
interface A {
<T, U extends V<T>> T f(U v);
}
You can get close to what you want by taking multiple generic arguments at the interface level and none at the function level.
interface A<T, S extends V<T>> {
public T f(S v);
}
class B<T> extends A<T, V1<T>> {
#Override // Here it gives error: Method does not override method from its superclass
public T f(V1<T> v) {
return v.v1();
}
}
Note that this isn't quite the guarantee you were looking for, as someone could come along and write some class C extends A<Integer, V1<Integer>> that only works for integers and no other type. But to do that, you'd need something called higher-kinded polymorphism which is not supported in Java.
The definition of the method f in the subclass violates the Liskov substitution principle, which says that should be able to use a child instance whenever the parent is expected.
public <T> T f(V1<T> v)
Method f in the parent class expects V<T> as an argument. And V is a super type of V1 which means that the method declared by the child expects a more narrow type. I.e. the instance of a child is not able to handle all subtypes of V and hence can't substitute its parent.
And from the practical point of view, it's clearly not a valid method overriding (at least in Java). Method signatures should match exactly, otherwise it's a method overloading, which is the case here.
And you're getting a compilation error because you've applied #Override annotation and the compiler fails to find a method with matching signature in the parent class, and also because the contract defined by the interface A hasn't been't implemented.
The only exception related to the overriding of generic methods that we have is the possibility to override a method that expects a generic parameter like Collection<T> to be overridden by a non generified method that expects a Collection of row type (it was done in order to facilitate transition to generics when they were introduced in the language).

Implementing abstract methods in a subclass in Java

I've made my code as generic as possible to try and help people in the future. My abstract class has a method of the type class and and an input of the type class. In the class that extends the abstract, I try to implement that method to no avail. What am I doing wrong?
public abstract class A {
public abstract A method1(A arg);
}
public class B extends A {
#Override
public B method1(B arg) { "...insert code here"} // Error: The method method1(B) must override or implement a supertype method
}
To achieve what you want : associating the type of the argument to the declared class, you could use generics.
abstract class :
public abstract class A <T extends A<T>> {
public abstract T method1(T arg);
}
concrete class :
public class B extends A<B> {
#Override
public B method1(B arg) {
...
return ...
}
}
Think about the Liskov substitution principle: in order to be indistinguishable from a superclass, the subclass must accept all of the same parameters that the superclass would; and return something that the superclass might.
Another way to put this is that the subclass method can:
Return a more specific type that the superclass method (since this is a value that the superclass might return); for example, if the superclass returns Object, the subclass can return a String, because all Strings are Objects.
This is called a covariant return type, and is permitted in Java. Subclasses can not only return more specific return types, they can also throw more specific checked exceptions than the superclass; but they can also not declare that they throw the checked exceptions thrown by the superclass method.
Accept a more general type than the superclass method (since this allows the subclass to accept all parameters that the superclass would).
This would be called a contravariant parameter type; but it is not permitted in Java. The reason is to do with the way that overloads are selected in Java: unfortunately, the method signatures (which includes the parameter types, but not the return type) have to be identical.
The relevant section of the language spec is JLS Sec 8.4.8.3.
Your problem is making the parameter type B: this is more specific than A, so an instance of B is not substitutable for an instance of A, because A.method1 accepts a parameter A, whereas B.method1 does not.
Make B.method1 take a parameter of type A.
The type and no of parameter should remain. The return type, if it is of primitive type, should remain same, but if it is of reference type then it can be of subclass type.
In your case change this public B method1(B arg) { "...insert code here"} to public B method1(A arg) { "...insert code here"}
Every thing you have written is right except overidden method argument type,you can't change the signature of superclass abstract method while overiding in subclass.
public abstract class A {
public abstract A method1(A arg);
}
public class B extends A {
#Override
public B method1(A arg) { "...insert code here"} // Error: The method method1(B) must override or implement a supertype method
}
The contract of A.method1 means that every object that is an A must have a method1 which can take any A object.
In the case of B.method1, it can take a B object, but it cannot take another A.

Why In This Case , Overriding Setter Method Is Not Working

sorry about title since i couldn't find a better one so any edit on that will be appreciated.
consider these classes :
public interface GlobalDashlet {
public Collection<? extends GlobalDashletSetting> getSettings();
public void setSettings(Collection<? extends GlobalDashletSetting> settings);
}
public class Dashlet implements GlobalDashlet {
private Collection<DashletSetting> settings;
public Collection<DashletSetting> getSettings(){
return settings;
}
//This Wont Work
public void setSettings(Collection<DashletSetting> settings) {
this.settings = settings;
}
//This Will Work
public Collection<DashletSetting> getSettings(){
return settings;
}
}
public class DashletSetting implements GlobalDashletSetting {
}
Why overriding the setter method(i mean the way that i have done) wont work (the dashlet class complains about the unimplemented method) but overriding the getter method works?
how can i fix it? i need to be able to implement setter methods too (like the way that i have override the getter methods) because i have to serillize the Dashlet class with jackson mapper and Jackson can not determine the actual type of and object at run time without additional information on super classes.
The reason is that return types may be covariant.
You can always return a more specific type (i.e. a subtype) when overriding a method. A more comprehensible example is the following:
class NumberProvider {
Number getNumber() { return 1.23; }
}
class IntegerProvider extends NumberProvider {
// Returning a more specific type when overriding:
#Override
Integer getNumber() { return 42; }
}
The type Collection<DashletSetting> is a proper subtype of Collection<? extends GlobalDashletSetting>. See the section about Which super-subtype relationships exist among instantiations of generic types? in the Generics FAQ.
For the setter, this does not work. The short reason why it does not work is: It is not type safe. An example of where the type safety is violated is easy to find, although it may seem a bit contrived at the first glance:
// This is the interface as it was defined:
public interface GlobalDashlet {
public void setSettings(Collection<? extends GlobalDashletSetting> settings);
}
public class Dashlet implements GlobalDashlet {
// Assume this was working:
public void setSettings(Collection<DashletSetting> settings) {
// Then you could add a "DashletSetting" here:
settings.add(new DashletSetting());
}
}
// But someone who CALLED this method may not have given it
// a Collection<DashletSetting>, but maybe a collection
// like Collection<SpecialGlobalDashletSetting>:
Collection<SpecialGlobalDashletSetting> settings = ...;
GlobalDashlet dashlet = new Dashlet();
// Based on the method signature that was defined in the interface,
// this would be possible:
dashlet.setSettings(settings);
// Now, the "settings" collection WOULD contain a simple "DashletSetting",
// although it should only contain "SpecialGlobalDashletSetting" instances
// This would cause a ClassCastException sooner or later
The example may look a bit confusing. Again, it's more intuitive with the "simple" types like Number and Integer, but it boils down to the same problem: If a more specific type was allowed for the setter method, then the type safety may be violated.
Because overrided method can not restrict the scope of input variable. Original method can accept anything which extends GlobalDashletSetting class but, but overriden method isrestricting to only one subclass of GlobalDashletSetting class
Because it has different signatures.
Collection<DashletSetting> is not Collection<? extends GlobalDashletSetting>
you need to override the exact signature, not part of it.
if you have method that takes Object, you cant override it with method that takes String even the String extends Object
in youre case, Collection<DashletSetting> and Collection<? extends GlobalDashletSetting> are actually different classes, you have to override with the same class.
the getter is working since it has the same signature (same method name and no params), thats not the case in the setter

Java: Generic accepting only enum types

Assuming that I have a basic enum like:
public enum Color { Red, Green, Blue}
How can one write a generic class which only accepts "enum classes" so that a concrete instantiation of that generic class might look like MyClass<Color>?
Edit:
What a actually want to do is to write a generic abstract class containing a function returning all enum "entries" as list:
public abstract class EnumListBean<E extends Enum<E>> {
public List<E> getEnumList() {
return Arrays.asList(E.values());
}
}
While Day.values() is available E.values() is not. What i am doing wrong here?
public class EnumAcceptor<E extends Enum<E>> {
...
}
Use E as a type inside your class.
See Istvan Devai for answer to original question.
For the follow up, methods like values() are static methods, so you're out of luck trying to get that from a generic parameter. As a poor solution, you can pass the enum's Class object into the constructor. and use Class.getEnumConstants. But you might as well pass MyEnum.values() into the constructor rather than the class, and so avoid reflection altogether. It's a real shame there isn't a sensible enum metaclass.
An enum really declares a class derived from Enum. As such, you can use:
public class MyClass<T extends Enum> { }
Note that #Istvan's solution can only accept elements of the enum, which is fine if that is all you want.
Although you cannot pass the enum itself as a parameter (because it does not actually have an object equivalent) you can specify that you must receive the class of the enum in your constructor and derive the enum's details from that:
public class EnumAcceptor<E extends Enum<E>> {
public EnumAcceptor(Class<E> c) {
// Can get at the enum constants through the class.
E[] es = c.getEnumConstants();
}
enum ABC {
A, B, C;
}
public static void main(String args[]) {
EnumAcceptor<ABC> abcAcceptor = new EnumAcceptor<ABC>(ABC.class);
}
}
You can't use E.values() due to type erasure -- the type of E is not available at run-time.
For the specific case in your question, you're probably better off using Guava's Lists.newArrayList:
List<Color> days = Lists.newArrayList(Color.values());

Categories

Resources