I have an enum which is implements an interface. Enum:
enum MyEnum implements MyInterface {
ONE, TWO, THREE;
#Override
public MyEnum getFirst() {
return ONE;
}
}
Interface:
interface MyInterface<T extends Enum<T>> {
T getFirst();
}
Also I have a generic class with bounds:
class MyClass <T extends Enum<T> & MyInterface> {
private T firstElement;
private Class<T> enumType;
MyClass (Class<T> enumType) {
this.enumType = enumType;
}
}
So the main idea is to pass any enum (which is implements MyIterface) into constructor and then work with its constants. And this works for me. But also I want to store this first element into firstElement private field. I tried something like this:
firstElement = ((MyInterface)enumType).getFirst();
But still no success. I can't cast java.lang.Class<T> to MyInterface. Any ideas how to achieve this? Thanks in advance!
UPDATE: My problem is not about how to take the first enum constant. I know about .ordinal() and .values()[0];. I want to create reusable generic class and use it with any enums, marked by some interface.
Ok, let it not be getFirst() method. Let it be getDefault()
I think you could use Supplier<T> as an argument for your constructor instead of Class<T>:
class MyClass<T extends Enum<T> & MyInterface<T>> {
private T firstElement;
private Class<T> enumType;
#SuppressWarnings("unchecked")
MyClass (Supplier<T> enumSupplier) {
T actualEnum = enumSupplier.get();
this.enumType = (Class<T>) actualEnum.getClass();
this.firstElement = actualEnum.getFirst();
}
}
That cast throws a warning, but it can be safely suppressed, since Supplier<T> will return an instance of T, and T is both Enum<T> and MyInterface<T>, so the class of actualEnum will always be Class<T>.
I would like to suggest you a few corrections: as MyInterface is generic, you should always use it along with a generic type (this is why I've declared MyClass as MyClass<T extends Enum<T> & MyInterface<T>>). The same goes for MyEnum: it should be defined as MyEnum implements MyInterface<MyEnum>.
With the above changes in place, you can now create an instance of MyClass as follows:
MyClass<MyEnum> myClass = new MyClass<>(() -> MyEnum.THREE); // Or ONE or TWO
System.out.println(myClass.firstElement); // ONE
From your context I think you need getFirst() because you want to get the first value of a enum. However, you don't need getFirst() at all. All you need is this:
class <T extends Enum<T> & MyInterface> MyClass {
private T firstElement;
private Class<T> enumType;
MyClass (Class<T> enumType) {
this.enumType = enumType;
firstElement = enumType.getEnumConstants()[0];
}
}
You can just remove all those getFirst() in all of your classes.
You can call getFirst only on an enum object which implements MyInterface but not on its class. You can write:
firstElement = enumType.getEnumConstants()[0].getFirst();
interface MyInterface {
MyInterface getFirst();
MyInterface[] getConstants();
}
enum MyEnum implements MyInterface {
ONE, TWO, THREE;
#Override
public MyInterface getFirst() {
return ONE;
}
#Override
public MyInterface[] getConstants() {
return new MyInterface[] {ONE, TWO, THREE};
}
}
class MyClass {
private MyInterface firstElement;
MyClass (MyInterface enumType) {
this.firstElement = enumType.getFirst();
}
}
So, using the above design I think you can "pass any enum (which is implements MyInterface) into constructor and then work with its constants."
Related
I have two classes that extend a common base class. The base class has code that, for one concrete subclass, needs to know the Class of the other concrete subclass. So, given Foo and Bar extending Base, an instance of Foo needs to know Bar.class, and an instance of Bar needs to know Foo.class.
And, silly me, I'm trying to Do the Right Thing and use Java generics to ensure that the subclasses return a valid Java class object, one that extends the base class.
So, I tried this:
class Base {
abstract protected <T extends Base> Class<T> getOtherClass();
}
The compiler seems reasonably happy with that construction. The problem comes in the implementations.
First, I tried:
class Foo extends Base {
#Override
protected <T extends Base> Class<T> getOtherClass() {
return Bar.class;
}
}
(where Bar also extends Base)
That complains that I have a type mismatch in the return value, and it requires a cast.
Then, I tried:
class Foo extends Base {
#Override
protected Class<Bar> getOtherClass() {
return Bar.class;
}
}
Now the compiler complains about needing a cast at Class<Bar>.
Then I tried:
class Foo extends Base {
#Override
protected Class<Base> getOtherClass() {
return Bar.class;
}
}
Now I get both complaints: needing a cast in the Class<Base> and in the return value.
Is there a way of expressing this that avoids any casts?
abstract class Base<T extends Base> {
abstract Class<T> getOtherClass();
}
class Foo extends Base<Bar> {
#Override Class<Bar> getOtherClass() { return Bar.class; }
}
...or...
abstract class Base {
abstract Class<? extends Base> getOtherClass();
}
class Foo extends Base {
#Override Class<Bar> getOtherClass() { return Bar.class; }
}
From the Spring reference documentation, a converter factory can be implemented as follows:
final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToEnumConverter(targetType);
}
private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {
private Class<T> enumType;
public StringToEnumConverter(Class<T> enumType) {
this.enumType = enumType;
}
public T convert(String source) {
return (T) Enum.valueOf(this.enumType, source.trim());
}
}
}
However, Enum is a raw type here. If I parameterize Enum and have my IDE (Eclipse Mars) add the method, it results in the following:
final class StringToEnumConverterFactory<T extends Enum<T>> implements ConverterFactory<String, Enum<T>> {
#Override
public <T extends Enum<T>> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToEnumConverter<T>(targetType);
}
private final class StringToEnumConverter<T extends Enum<T>> implements Converter<String, T> {
private Class<T> enumType;
public StringToEnumConverter(Class<T> enumType) {
this.enumType = enumType;
}
public T convert(String source) {
return Enum.valueOf(this.enumType, source.trim());
}
}
}
But now I have two issues:
The following compiler error appears:
The type StringToEnumConverterFactory<T> must implement the inherited abstract method ConverterFactory<String,Enum<T>>.getConverter(Class<T>)
The type parameter T is hiding the type T.
Can you someone please explain how to properly change the StringToEnumConverterFactory to have Enum parameterized?
This actually turns out to be (perhaps surprisingly, not sure) a pain in the neck, because of the way Enum.valueOf is declared.
To get the example as-is to compile, you'd end up with something like this:
class StringToEnumConverterFactory<T extends Enum<T>>
implements ConverterFactory<String, T> {
// ^
#Override
public <E extends T> Converter<String, E> getConverter(Class<E> targetType) {
// ^^^^^^^^^^^ ^ ^
return new StringToEnumConverter<E>(targetType);
// ^
}
// ...
}
This, unfortunately, doesn't actually help us out because then you can only ever have e.g. a StringToEnumConverterFactory<Planet> or StringToEnumConverterFactory<Color> which defeats the purpose of the generalization the generic method offers. And you won't be able to make a StringToEnumConverterFactory<?> or StringToEnumConverter<Enum<?>>.
We don't actually want a type variable declared on the class, so the declaration we desire is like this, with a wildcard:
class StringToEnumConverterFactory
implements ConverterFactory<String, Enum<?>> {
#Override
public <E extends Enum<?>> Converter<String, E> getConverter(
Class<E> targetType) {
return new StringToEnumConverter<E>(targetType);
}
// ...
}
But this creates problems for us when we try to call Enum.valueOf because its type variable declaration is more restrictive. We won't ever be able to call it without some sort of cowboy unchecked cast (which is provably safe, but only with Enum):
return (T) Enum.valueOf((Class) enumType, source);
Fortunately, we can still otherwise bypass this through the Class object:
for (T constant : enumType.getEnumConstants())
if (constant.name().equals(source))
return constant;
The final code would be something like this:
class StringToEnumConverterFactory
implements ConverterFactory<String, Enum<?>> {
#Override
public <E extends Enum<?>> Converter<String, E> getConverter(
Class<E> targetType) {
return new StringToEnumConverter<E>(targetType);
}
static class StringToEnumConverter<E extends Enum<?>>
implements Converter<String, E> {
Class<E> enumType;
StringToEnumConverter(Class<E> enumType) {
this.enumType = enumType;
}
#Override
public E convert(String source) {
source = source.trim();
// perhaps we would cache the constants somewhere
for (E constant : enumType.getEnumConstants())
if (constant.name().equals(source))
return constant;
// also some people like to return null
throw new IllegalArgumentException(source);
}
}
}
So no raw types, no unchecked casts, but kind of a pain in the neck.
I think it may not be possible to define a converter factory as you are trying to do. The type you really want is a ConverterFactory<String, R>, where R extends Enum<R>. Note that I have used the type R here to match the documentation, in order to avoid confusion.
The API of the ConverterFactory interface then requires us to implement the following method:
public <T extends R> Converter<String, T> getConverter(Class<T> targetType) {
???
}
We know that it is in fact impossible to extend enum types, and therefore the only possibility is that T and R are the same type. However this is not known by the compiler, and therefore we cannot make any other assertions about the type T other than that it extends R.
In particular, we do not know whether T extends Enum<T>. We therefore cannot use T in a StringToEnumConverter<T> as you have defined it, since we cannot use Class<T> in Enum.valueOf.
I think you therefore need to continue using the original version without generics. It is slightly unfortunate that it requires an unchecked cast, but keep in mind that generics are erased at compile time, so all that will be left is a cast to Enum anyway.
I have an interface:
public MyInterface {};
And few enums which implement MyInterface as:
public enum MyFirstEnums implements MyInterface{};
In some another class, I need a method to return Class object such that
the Class should be like MyFirstEnums, which extends enum and implements MyInterface.
The return type of method should be: <E extends Enum<?> & MyInterface>, which should allow returning MyFirstEnums.class and like enums
I tried doing it like:
public <E extends Enum<?> & MyInterface> Class<E> getClazz(){
return MyFirstEnums.class;
}
but this give me error as:
Type mismatch: cannot convert from Class<MyFirstEnums> to Class<E>
What am I missing here?
At other place, I tried a method which takes such type of class as an argument and that worked fine:
public <E extends Enum<?> MyInterface> void doSomething(Class<E> myClazz){};
//it rightly checks the type of myClazz while calling this method
You can't just return the class object of MyFirstEnum. Your method is declared to return a class object that corresponds to an enum and implements MyInterface but it could be an enum other than MyFirstEnum that also meets this criteria. Imagine you have another enum:
public enum MySecondEnum implements MyInterface { }
You could also do:
Class<MySecondEnum> clazz = getClazz();
The compiler infers the type argument from the target return type of clazz (E is inferred as MySecondEnum). In this case, clearly a runtime exception is likely to occur. For example, when you try to instantiate an object from the returned class, you would get a java.lang.InstantiationException.
Note that your method does not actually use the type argument, so why have it generic in the first place?
If you want a "generic" way to return class objects for each enum implementing the interface, you can do something like:
abstract class EnumProvider<E extends Enum<?> & MyInterface> {
...
public abstract Class<E> getClazz();
}
class MyFirstEnumProvider extends EnumProvider<MyFirstEnums> {
...
#Override
public Class<MyFirstEnums> getClazz() {
return MyFirstEnums.class;
}
}
I would try some response:
You want to define a method which return some class type which is not fully defined, but which respects: extends Enum & MyInterface.
And your Class is not passed to the method.
I have a doubt it is not possible or safe.
I would :
1 pass a Class I want as an argument
2 inverse the test: I test inside if Class< E> extends Enum & MyInterface and MyFirstEnum.class and if MyFirstEnum.class extends class< E>
3 of course Class result=MyFirstEnum.class; can be more sophisticated and not known before...
This compiles (because tests are made at runtime) but I dont know if it can help you.
public <E> Class<E> getClazz(Class< E> _return_class) throws Exception
{
Class result=MyFirstEnum.class;
if (MyInterface.class.isAssignableFrom(_return_class) )
if (Enum.class.isAssignableFrom(_return_class))
if (_return_class.isAssignableFrom(result))
return (Class<E>) result;
throw new Exception("Bad Class");
}
I'm sure this is a duplicate, but the keywords for my search are too common... I get a lot of hits, for things I'm not looking for. I'm coming from C#, and Java generics seem to be a bit behind the .NET implementation, so this is pretty frustrating for me.
I have an abstract class BaseRepository like so:
public abstract class BaseRepository<T, K> implements Repository<T, K> {
private Class<T> type;
private Class<K> keyType;
public BaseRepository(Class<T> clazz, Class<K> kClazz) {
type = clazz;
keyType = kClazz;
}
protected Class<T> getType() {
return type;
}
protected Class<K> getKeyType(){
return keyType;
}
}
Now I want to derive from my base class with an EmployeeRepository like so:
public class EmployeeRepository extends BaseRepository<Employee, UUID>{
}
With c#, I would not need to make such heroic efforts to instantiate the base class, but it seems java's implementation of generics requires you to pass the generic type(s) in the constructor.
So how do I create a parameterless constructor for my EmployeeRepository class that instantiates the base class with an entity type of Employee and a key type of UUID? I want to be able to write this:
EmployeeRepository foo = new EmployeeRepository();
... and have it instantiate the abstract class with Class<Employee> and Class<UUID>.
AFAIK, there is no way round this other than invoking the superclass constructor from the default subclass constructor thus:
public EmployeeRepository() {
super(Employee.class, UUID.class);
...
}
You could use reflection to determine the type of the generic arguments.
public abstract class BaseRepository<T, K> implements Repository<T, K> {
private Class<T> type;
private Class<K> keyType;
public BaseRepository() {
Type[] actualTypes = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();
this.type = (Class<T>)actualTypes[0];
this.keyType = (Class<K>)actualTypes[1];
}
protected Class<T> getType() {
return type;
}
protected Class<K> getKeyType(){
return keyType;
}
}
However, the real question is: why do you want to have the types?
As an alternative, use the Builder pattern:
public class EmployeeRepository extends BaseRepository<Employee, UUID>{
public static EmployeeRepository newInstance() {
return new EmployeeRepository(Employee.class, UUID.class);
}
...
}
EmployeeRepository foo = EmployeeRepository.newInstance();
I'm having trouble finding a way to do this in a way that doesn't seem wrong, given the following
public interface IType {}
public interface IMode {}
public interface Factory<T extends IType> {
IMode get(T o);
Class<T> getIType();
}
I have the above interfaces and a large list on classes the implement both IType and IMode with corresponding factories.
I need to be able to convert from one to the other, for example,
public class A implements IType {}
public class One implements IMode {}
public class AToOne implements Factory<A> {
public IMode get(A o){
return new One();
}
public Class<A> getIType(){
return A.class;
}
}
Given that there is a 1 to 1 mapping of these classes, ie for every concrete IType there is one and only one concrete IMode with corresponding factory, how would I go about converting a list of ITypes to a list of IModes?
ie.
private List<Factory<? extends IType>> factoryList;
public List<IMode> getConversions(List<? extends IType> types){
???
}
My first try did not go so well,
//Fill this using the getIType() method from each factory
Map<Class<IType>, Factory<? extends IType>> factoryList = new HashMap<Class<IType>, Factory<? extends IType>>();
public List<IMode> getConversions(List<IType> types){
List<IMode> modes = new ArrayList<IMode>();
for(IType type : types){
//Derp
Factory<? extends IType> factory = factoryList.get(type.getClass());
//Error
factory.get(factory.getIType().cast(type));
}
}
Error:
The method get(capture#12-of ? extends IType) in the type
Factory<capture#12-of ? extends IType>
is not applicable for the arguments (capture#14-of ? extends IType)
Like I mentioned in my comment, you just need to use a generic helper method to access the map, which performs an unchecked cast from Factory<? extends IType> to a Factory<T> where T matches the type of what's passed in:
Map<Class<? extends IType>, Factory<? extends IType>> factoryList =
new HashMap<Class<? extends IType>, Factory<? extends IType>>();
private <T extends IType> IMode convert(T iType) {
//unchecked cast - implementation must guarantee map holds correct data
Factory<T> factory = (Factory<T>)factoryList.get(iType.getClass());
//then convert
return factory.get(iType);
}
You can call this helper method from the loop:
public List<IMode> getConversions(List<IType> types) {
List<IMode> modes = new ArrayList<IMode>(types.size());
for (IType type : types) {
IMode iMode = convert(type);
modes.add(iMode);
}
return modes;
}
The simple solution is the following:
interface IFoo {
}
interface IBar {
}
private static class Foo implements IFoo {
}
private static class Bar implements IBar {
}
interface IFoo2IBarConverter<B extends IBar, F extends IFoo> {
B convert(F foo);
}
private static class Foo2BarConverter implements IFoo2IBarConverter<Bar, Foo> {
public Bar convert(Foo foo) {
return new Bar();
}
}
private static class IFoo2IBarFactory {
private static HashMap<Class<? extends IFoo>, IFoo2IBarConverter<? extends IBar, ? extends IFoo>> converters = new HashMap<>();
static {
converters.put(Foo.class, new Foo2BarConverter());
}
public static<F extends IFoo, B extends IBar> B convert(F foo) {
// ugly unchecked cast here
IFoo2IBarConverter<B, F> converter = (IFoo2IBarConverter<B, F>) converters.get(foo.getClass());
return converter.convert(foo);
}
}
public static void main(String[] args) {
Foo foo = new Foo();
IBar bar = IFoo2IBarFactory.convert(foo);
}
You just take a HashMap that maps a specific class that's a subtype of IFoo to some converter interface. The converter takes the IFoo instance and converts it into a IBar.. actually into the specific classes we want. Sadly we get an ugly cast in IFoo2IBarFactory.convert() and I don't think there's any way to avoid that one. Still at least it's only in one localized position and with the right comment and a SuppressWarning you can live with it, I'd think