How can I invoke name() inside an interface for an Enum? - java

I defined an interface for enum types.
interface MyInterface<E extends Enum<E> & MyInterface<E>> {
}
// e.g.
enum MyEnum implements MyInterface<MyEnum> {
}
Now I want to access name() method from a method defined in above interface.
interface MyInterface<E extends Enum<E> & MyInterface<E>> {
default void doSomeWithEnumName() {
// How can I access #name() method in here?
}
}

You can cast this to an Enum<?> and just access name().
System.out.println(((Enum<?>) this).name());
However, with the current set up, it is in fact possible for one to be naughty and create a non-enum class that implements your interface:
enum Bar implements MyInterface<Bar> {}
class Foo implements MyInterface<Bar> {}
Therefore, I would advise that you check the type of this first:
if (this instanceof Enum<?> enumThis) {
System.out.println(enumThis.name());
} else {
throw new RuntimeException("Only enums can implement this interface!");
}
(I can't think of how you would limit the interface to be only implementable only for enums - there are no "self" types in Java)

Related

How to return interface from generic class implementing the interface?

I want to make a method that accepts any class T that implements any interface I.
Then do something with the class and return the interface I that is implemented.
Here's what I've tried:
class MyLibrary {
public static <I, T extends I> I registerImplementation(Class<T> classImpl) {
I interfaceImpl = (I) classImpl.newInstance();
return interfaceImpl;
}
}
I'm then creating an interface and a class which implements that interface:
interface UserInterface {
void doSomethingDefined();
}
class UserClass_v1_10_R2 implements UserInterface {
#Override
public void doSomethingDefined() {
System.out.println("What this does is well-defined");
}
public void doVersionSpecificStuff() {
System.out.println("This is not in the interface, so don't really depend on this");
}
}
However, when I'm calling the method referencing UserClass, it returns the same class type T instead of the interface type I, allowing all the class methods which are not declared in the interface to be called.
I.e. in the statement below, even though registerImplementation() is declared to return a reference to UserInterface, the compiler sees the reference as pointing to an instance of UserClass_v1_10_R2, allowing access to the implementation's methods that are not in the interface.
MyLibrary.registerImplementation(UserClass_v1_10_R2.class).doVersionSpecificStuff();
Contrast this with the supposedly identical
UserInterface uiObj = MyLibrary.registerImplementation(UserClass_v1_10_R2.class);
uiObj.doVersionSpecificStuff(); // This does not compile
That's just how the compiler infers the type. If you compile with a special (undocumented) flag:
javac --debug=verboseResolution=all ...
you will see that:
Note: Deferred instantiation of method <I,T>registerImplementation(Class<T>)
MyLibrary.registerImplementation(UserClass_v1_10_R2.class).doVersionSpecificStuff();
^
instantiated signature: (Class<UserClass_v1_10_R2>)UserClass_v1_10_R2
Look at the instantiated signature: (Class<UserClass_v1_10_R2>)UserClass_v1_10_R2
So you need to add another argument, to take the interface:
public static <I, T extends I> I registerImplementation(Class<I> interfaceClass, Class<T> implClass) {
// do whatever checks you want if this is an interface or if a constructor can be called....
I interfaceImpl = null;
try {
interfaceImpl = interfaceClass.cast(implClass.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
return interfaceImpl;
}
Of course this raises the question if you have multiple interfaces, but that is something for you to think about.
It's possible to achieve this by passing the desired interface class as another argument to the method. This also allows to verify that the generic type class is an interface, as well as adding extra checks to make sure that the class implementing the interface can be instantiated.
public class MyLibrary {
public static <I> I registerImplementation(Class<I> interfaceClass, Class<? extends I> implClass) {
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException("Must be an interface class");
}
// Check constructor accessibility, etc...
if (Modifier.isAbstract(implClass.getModifiers())) {
throw new IllegalArgumentException("Must be instantiable");
}
return implClass.newInstance();
}
}
This returns an implementation of the interface passed as the first parameter. The second parameter's bounded type Class<? extends I> means an explicit cast is not required:
// This returns UserInterface
MyLibrary.registerImplementation(UserInterface.class, UserClass_v1_10_R2.class);

How to set type parameter of interface's implementing class?

I want to know if is it possible to set a paramenter's type that is the type of the class that implements a given interface. Seeing some code the question will become more clear:
interface A {
A sum (???? another);
}
class AClass implements A {
private int internalStuff;
A public sum (???? another) {
// I want to access another.internalStuff in a type safe fashion
}
}
Of course I can substitute ???? with A type, and inside AClass.sum, cast it to AClass but that is ugly. Can "????" be replaced with some meaningful type declaration?
There is no self-type in Java, so you have to do a little trick to achieve this.
You can add a type parameter with a recursive type bound to the interface. The implementing class sets this parameter to its own type. Like this:
interface A<T extends A<T>> {
A sum (T another);
}
class AClass implements A<AClass> {
private int internalStuff;
public A sum(AClass another) {
// ....
}
}
There is nothing stopping AClass from doing implements A<SomeOtherAClass> though. You have to trust the implementing class to provide the correct type parameter.

Apply generically enum member or method

I have an interface ServiceArgument which defines a size() promise.
public interface ServiceArgument {
public int size ();
}
Some of my enum types implement this interface
public enum StringCode implements ServiceArgument {
FOO,
BAR,
BACON,
public int size() {
return values().length;
}
}
Some of my class follow a EnumService abstract class.
public abstract class EnumService {
abstract void query (Enum<? extends ServiceArgument> e);
}
And to wrap it up, some class extends this abstract class :
public class ServiceTranslation extends EnumService implements Serializable {
/**some code and ctors and transient stuff etc **/
#Override
void query (Enum<? extends ServiceArgument> e) {
//line that matters :
if (e.ordinal() >= e.size()) {
throw InvalidStringCodeAsked();
}
}
My problem is, I can't use e.size() at the last line, because I wouldn't use FOO.size() in my example enumeration.
Is there a way to, either :
1) specialise what the query method accepts as a parameter in the concrete implementations of EnumService
2) get the concrete type of the Enum called in ServiceTranslation.query(MYSTERIOUS.ENUM), in order to be able to call ConcreteENUM.size(). or even ConcreteEnum.values().length, it's the same.
3) even filter everything that is not from the right enumerated type to throw directly a InvalidEnumeratedTypeException through method override, but i'm not familiar with multiple overriding.
4) something I didn't think of
Edit : #shmosel in the comment is right, even if I get the wrong enumeration as argument, it will never be greater than its size. No point in comparing it to its size.
How about this one?
public abstract class EnumService {
abstract <T extends Enum<T> & ServiceArgument> void query (T e);
}
public class ServiceTranslation extends EnumService implements Serializable {
#Override
<T extends Enum<T> & ServiceArgument> void query (T e) {
if (e.ordinal() >= e.size()) {
throw InvalidStringCodeAsked();
}
}
}

Enforce subclass to declare a enum

Can I enforce child classes to create a enum in them?
class Document<T extends Enum<T>>{
Map<T, String> fields;
}
class TextDocument extends Document<TextDocument.Field>{
public enum Field{
...
}
}
How can I enforce any implementation of Document to have an enum named Field within it? In the above example, TextDocument can extend Document with some other enum (say GraphDocument.Field) as well which shouldn't be allowed. How can I create this restriction? I need to enforce this rule to subclasses - "You must have your own enum". Is this even possible? By some hacky way? Any ideas?
In short, you can't. However, you can force it to return an array of the values of a particular enumeration. You can also force the enumeration to implement an interface.
public interface SomeInterface {
// any methods you want to be able to perform on the enums
}
public abstract class SomeSuperClass<T extends SomeInterface> {
abstract T[] getSome();
}
public class SomeSubclass extends SomeSuperClass<SomeInterface> {
public enum SomeEnum implements SomeInterface {
testEnum {
// interface implementation
}
}
public SomeInterface[] getSome() {
return SomeEnum.values();
}
}
This is a pretty awkward solution, but it works.

Enum<? extends interface>

I'm attempting to have a collection of enums that extend a common interface, so something like:
interface Fooable
{
void someCommonMethod();
}
enum E1 implements Fooable
{
// some enumuerations and a definition for someCommonMethod()
}
enum E2 implements Fooable
{
// some different enumerations and a different definition for someCommonMethod()
}
and then make use of this elsewhere by enforcing both that a variable is a Enum and implements the interface. So something along the lines of..
bar(Enum<? extends Fooable> fe)
{
fe.ordinal();
fe.someCommonMethod();
}
However, so far I seem to have to cast fe in order to treat it as implementing the interface, i.e.,
bar(Enum<? extends Fooable> fe)
{
fe.ordinal();
((Fooable)fe).someCommonMethod();
}
and while this should be safe... it seems suboptimal and that I may be overlooking something. Of course if I try to just pass the param as a Fooable then I wind up casting to treat it as a Enum and not only is this no-gain I'm now not even safe. See following:
bar(Fooable fe)
{
// potentially unsafe cast!
((Enum<?>)fe).ordinal();
fe.someCommonMethod();
}
Is there anything I'm overlooking or is the
Enum<? extends Fooable>
about as close to a 'good' solution as I'll get?
I am relatively new to Java and am still catching myself trying to use it like C or C++ so if I'm treating it like a hammer instead of a saw or overlooking something stupidly simple feel free to point it out :)
This means that T extends Enum and implements Fooable:
<T extends Enum<T> & Fooable>
Thus your method can be written as:
<T extends Enum<T> & Fooable> void bar(T fe) {
fe.ordinal();
fe.someCommonMethod();
}
One option you have is to add any of the methods from Enum you need onto Fooable or create a new interface that extends Fooable and adds the Enum methods you need.
Example:
interface Fooable {
void someCommonMethod();
}
interface FooableEnum extends Fooable {
int ordinal();
}
enum E1 implements FooableEnum {
// Implement someCommonMethod.
// ordinal() is already implemented by default.
}
Once you've done this you can use FooableEnum as the parameter type in your method signature and not worry about any of the generic stuff.

Categories

Resources