I'm trying to make an interface with a default method that returns valueOf(string) of that enum or null it there isn't any, so I can easily implement it without needing to paste the non-generic variant of this code in all classes in which I need such thing. So I tried doing this but it doesn't compile:
public interface EnumWNull<T extends Enum<T>> {
default T getEnumOrNull(String value){
try {
return Enum.valueOf(T /*Error: expression expected*/, value);
}catch (Exception e){
return null;
}
}
}
I don't understand why. And I actually know I can just read all the values and search for it manually, however I want to know a better way than that for the sake of learning and elegance(and I feel like there should be a better way, if there isn't, what's the purpose of the static variant of valueOf ?).
You can't do it without passing a Class object. You'll need to mimic the signature of Enum.valueOf():
static <T extends Enum<T>> T getEnumOrNull(Class<T> enumType, String name) {
try {
return Enum.valueOf(enumType, name);
} catch (IllegalArgumentException e) {
return null;
}
}
Instead of implementing an interface with a default method, I suggest creating a static utility method. #shmosel's answer nicely does this, but I suggest using Optional to convey that the method can return null (I've forked his code).
public static <T extends Enum<T>> Optional<T> getEnumValue(Class<T> enumType, String name) {
try {
return Optional.of(Enum.valueOf(enumType, name));
} catch (IllegalArgumentException e) {
return Optional.empty();
}
}
public static <T extends Enum> T getEnumOrNull(Class enumType, String name) {
return nonNull(name) ? Enum.valueOf(enumType, name) : null;
}
Related
As of Java 8 you can have default or static methods implemented in Interfaces as the below
public interface DbValuesEnumIface<ID, T extends Enum<T>> {
T fromId(ID id);
ID getId();
static String getDescriptionKey(){
return "this is a test";
}
}
I would like to declare the above with the static method having a signature that uses bounds defined by the implementing classes since the method's implementation should be the same for all,with the only thing different should be the generics declared, as such:
public interface DbValuesEnumIface<ID, T extends Enum<T>> {
public static T fromId(ID id) {
if (id == null) {
return null;
}
for (T en : T.values()) {
if (en.getId().equals(id)) {
return en;
}
}
}
ID getId();
String getDescriptionKey();
}
...
public enum Statuses implements DbValuesEnumIface<Integer,Statuses>
which breaks because T and ID are not static and cant be referenced from a static context.
So, how should the above be modified to compile successfully and if thats not possible, how the above should be implemented to achieve the desired purpose while avoiding code duplication within implementing classes .
Since there is no relationship between static methods and the class’ type parameters, which describe how instances are parameterized, you have to make the static method generic on its own. The tricky part is to get the declarations right to describe all needed constraints. And as this answer already explained, you need to a a Class parameter, as otherwise, the implementation has no chance to get hands on the actual type arguments:
public interface DbValuesEnumIface<ID, T extends Enum<T>> {
public static
<ID, T extends Enum<T>&DbValuesEnumIface<ID,T>> T fromId(ID id, Class<T> type) {
if (id == null) {
return null;
}
for (T en : type.getEnumConstants()) {
if (en.getId().equals(id)) {
return en;
}
}
throw new NoSuchElementException();
}
ID getId();
String getDescriptionKey();
}
Note that the type parameters of the static method are independent from the class’ type parameter. You may consider giving them different names for clarity.
So now, given you enum Statuses implements DbValuesEnumIface<Integer,Statuses> example, you can use the method like Statuses status = DbValuesEnumIface.fromId(42, Statuses.class);
Note that for default methods, it is possible to access the actual type, as a method providing the enum type will be provided by the implementation. You only have to declare the presence of the method within the interface:
public interface DbValuesEnumIface<ID, T extends Enum<T>&DbValuesEnumIface<ID,T>> {
public default T fromId(ID id) {
if (id == null) {
return null;
}
for (T en : getDeclaringClass().getEnumConstants()) {
if (en.getId().equals(id)) {
return en;
}
}
throw new NoSuchElementException();
}
Class<T> getDeclaringClass();//no needed to implement it, inherited by java.lang.Enum
ID getId();
String getDescriptionKey();
}
However, the obvious disadvantage is that you need a target instance to invoke the method, i.e. Statuses status = Statuses.SOME_CONSTANT.fromId(42);
There is no easy way as far as I can tell, first you need to change your method to default, you can read more here of why you can't use generics in a static context.
But even if you change it to default things are still not going to work, since you need to pass an instance or class type of the enum to that method, something like this:
public default T fromId(ID id, Class<T> t) {
if (id == null) {
return null;
}
for (T en : t.getEnumConstants()) {
// dome something
}
return null;
}
Now you are hitting another problem, inside fromId - the only thing that you know is that T extends an enum - not your enum may be, thus getId (which seems that your enums have) are simply not known by the compiler.
I don't know an easy way to make this work besides declaring an interface, like :
interface IID {
public int getId();
}
making your enum implement it:
static enum My implements IID {
A {
#Override
public int getId() {
// TODO Auto-generated method stub
return 0;
}
};
}
and change the declaration to:
public interface DbValuesEnumIface<ID, T extends Enum<My> & IID>
You can change from static to default and it will compile successfully.
default EvaluationStatuses fromId(Integer id)
I have a class with a couple of methods that convert from one generic type to another, but I want to return the original value if both: the argument type and the return type are the same. The best option I could come up with was to cast the argument type and wrap it in a try catch statement, but that seems dirty to me.
public WK wrapKey(K key) {...
public abstract class MyClass<K, V extends Comparable, WK, WV> extends BaseClass<Map<WK, WV>, KeyValueBean<K, V>> {
...
public WK wrapKey(K key) {
try {
return (WK) key;
} catch (Exception e) {
return null;
}
}
public WV wrapValue(V value) {
try {
return (WV) value;
} catch (Exception e) {
return null;
}
}
I thought the other option could be to specify the class type as an argument in the constructor or a setter method, and then use isAssignableFrom:
public WV wrapValue(V value) {
if (value.class.isAssignableFrom(this.getWrappedValueClass())){
return WK(V);
}
return null;
}
Is there any other way??
Java implements generics through type erasure, which means all type checks are performed at compile-time and then the generics are erased at runtime. Because of this, your code below actually does nothing at all:
public WV wrapValue(V value) {
try {
return (WV) value;
} catch (Exception e) {
return null;
}
}
At runtime, this is equivalent to:
public Object wrapValue(Object value) {
return value;
}
This method will never throw an exception, instead the caller of this method might, because the compiler adds an implicit cast at the call site.
Your second example won't even compile because you cannot do value.class. You would have to pass in the class types for both V and KV if you want to do this check.
In any case, your design seems overly complicated -- perhaps if you explain what you are trying to do, there might be a better solution.
I have a class which has several fields which are a subclass of another class. I want to quickly find all instances of that subclass within the top level class.
For example
public class TopClass {
private ClassIWant1 myVar1;
private ClassIWant2 myVar2;
private OtherJunk myVar3;
private Nested myVar4;
}
public class Nested {
private ClassIWant3 myVar11;
}
public class SuperClass {
}
public ClassIWant1 extends SuperClass {}
public ClassIWant2 extends SuperClass {}
public ClassIWant3 extends ClassIWant1 {}
If I were to run that example through with an instance of TopClass I would expect to get a List containing the values for myVar1, myVar2, and myVar11.
I have a general idea of how to use reflection to do this manually, but I'm hoping that I don't have to reinvent the wheel. Is there a library that can do this?
I am familiar with ReflectUtils, but I am not sure if that can do this or not.
If I understand your request correctly, you're looking for something like this:
public class Test {
public static void main(String[] args) {
TopClass top = …; // initialise as appropriate
System.out.println(findFields(top, SuperClass.class));
}
private static <T> List<T> findFields(Object haystack, Class<T> needle) {
return findFields0(haystack, needle, new HashSet<Object>(), new ArrayList<T>());
}
private static <T> List<T> findFields0(Object haystack, Class<T> needle, Set<Object> visited, List<T> result) {
if (visited.contains(haystack)) return result; // we already searched this object
visited.add(haystack);
for (Field field : haystack.getClass().getFields()) {
field.setAccessible(true);
Object fieldValue = null;
try {
fieldValue = field.get(haystack);
} catch (IllegalAccessException e) {
// shouldn't happen
throw new RuntimeException(e);
}
if (needle.isAssignableFrom(field.getType())) {
result.add(needle.cast(fieldValue));
}
// recurse
findFields0(fieldValue, needle, visited, result);
}
return result;
}
}
This works by using the static types of the fields as declared. That is, if you declare a field as Object but it holds an instance of SuperClass or one of its descendants, it won't be found. It will also return nulls if the fields have them set as the value. I have no idea what this will do about primitive types.
Disclaimer: Code was tested briefly on an optimistic example, I hold no responsibility if it causes your computer to catch fire.
Is this method what you're looking for?
I am refactoring some legacy code and have come across a problem which I'm sure has a elegant solution - but I can't quite get there.
Initially there were a load of classes which extended an abstract class BaseType. Each of these classes has a enum - XmlElementTag - with values specific to the class:
enum XmlElementTag {value1, value2, value3}
They each also have a method :
private XmlElementTag getTag(String s){
XmlElementTag ret = null;
try {
ret = XmlElementTag.valueOf(s);
} catch (Exception e) {
Log.e(this, s+" is not supported tag");
}
return ret;
}
Every class has this exact same getTag method, but obviously they are all referring to the XmlElementTag enum specific to the class they are in. So, I'd like to get rid of this code duplication if I can.
I thought that maybe I could use a marker interface to solve this problem, so created one as which each XmlElementTag enum now inherits and rewrote the getTag method and put it in the super class.
So I have this in each class:
private XmlElementTag implements GenericTag {value1, value2, value3};
And this in the BaseType superclass:
public interface GenericTag {}
protected GenericTag getTag(String tagName){
XmlElementTag tag = null;
try {
tag = XmlElementTag.valueOf(tagName);
} catch (Exception e) {
Log.e(this, tagName+" is not supported tag");
}
return tag;
}
But again this doesn't work as the BaseType super class doesn't know what XmlElementTag is; Java doesn't allow abstract class variables; and creating this element in the BaseType won't work, as the getTag code will always refer to this enum, rather than the one in the class which extends BaseType.
Can anyone point me in the correct direction?
I guess you could write a static generic helper method that did what getTag does. It would need to use reflection under the hood, and would most likely require you to pass the enumeration's Class object as a parameter.
But IMO, you shouldn't. The getTag() method is kind of wrong-headed. It is turning what is effectively bad input into a null. That's wrong from two perspectives:
In most contexts, "you gave me bad stuff" should not be treated as "you gave me nothing".
If you are not scrupulously careful, those null values are going to come back to bite you as NullPointerExceptions.
So really, your application code should either catch and deal with the IllegalArgumentException that arises when the conversion goes wrong, or it should allow the exception to bubble up to the top where it can be reported as (for instance) an error parsing the input stream.
(I don't think that an enum can either extend or be extended, so I don't think your enums can inherit a generic version of this class.)
You might be able to coalesce the XmlElementTag elements into a single enum and establish an EnumSet apropos to each derived type. There's an example here.
Addendum: In this scheme, getTag() would then become a single method of the combined enum. Each derived class would invoke getTag() using the Set that it considers valid. The method might have a signature such as this:
public static XmlElementTag getTag(Set valid, String s) { ... }
Unfortunately Java enums don't come with a good meta-class (Class is evil). However, all you really need here is the list (array) of the enum values.
As it's a private method, you might as well use composition.
import static java.util.Objects.requireNonNull;
/* pp */ class EnumFinder<E extends Enum<E>> {
private final E[] tags;
protected BaseType(E[] tags) {
this.tags = requireNonNull(tags);
}
public E getTag(String name) {
requireNonNull(name);
for (E tag : tags) {
if (name.equals(tag.name())) {
return tag;
}
}
Log.e(this, name+" is not supported tag"); // (sic)
return null; // (sic)
}
...
}
public class DerivedType {
private static final EnumFinder<XmlElementType> finder = // note, shared
new EnumFinder<>(XmlElementType.values());
...
finder.getTag(name)
...
}
(Create a Map<String,E> if you really want to. Unnecessary for reasonably sized enums.)
If you really want to use inheritance, then that is much the same. (Unfortunately as we are using an array, unless you add more boilerplate to your code, this code will create an unnecessary extra array per instance - probably not a significant issue, but may be.):
/* pp */ abstract class BaseType<E extends Enum<E>> {
private final E[] tags;
protected BaseType(E[] tags) {
this.tags = requireNonNull(tags);
}
public E getTag(String name) {
requireNonNull(name);
for (E tag : tags) {
if (name.equals(tag.name())) {
return tag;
}
}
Log.e(this, name+" is not supported tag"); // (sic)
return null; // (sic)
}
...
}
public class DerivedType extends BaseType<XmlElementType> {
public DerivedType() {
super(XmlElementType.values());
}
...
this.getTag(name)
...
}
You could use generics for that:
The Base is
public abstract class Base {
protected static <T extends Enum<T>> T getTag(Class<T> enumType, String s) {
T ret = null;
try {
ret = Enum.valueOf(enumType, s);
} catch (Exception e) {
System.err.println(s + " is not supported tag");
}
return ret;
}
protected abstract <T extends Enum<T>> T getTag(String s);
}
Your numerous classes have a shorter getTag() (and all the logic is in the Base)
public class ClassA extends Base {
enum XmlElementTag {
UL, LI
}
#Override
protected XmlElementTag getTag(String s) {
return Base.getTag(XmlElementTag.class, s);
}
}
(same thing for ClassB)
I think that you wanted to achieve something like this (correct me if I'm wrong):
interface GenericTag {
public GenericTag fromString(String str) throws IllegalArgumentException;
}
class BaseType {
protected GenericTag getTag(String tagName) {
GenericTag tag = null;
try {
tag = tag.fromString(tagName);
} catch (Exception e) {
Log.e(this, tagName+" tag is not supported");
}
return tag;
}
}
class ConcreteTypeA extends BaseType {
enum XmlElementTag implements GenericTag {
TAG1, TAG2;
public GenericTag fromString(String str) throws IllegalArgumentException {
return XmlElementTag.valueOf(str);
}
}
}
However, that will never work. You would need the fromString method to return an instance of appropriate class (in this case, enum) implementing the GenericTag, but the fromString method has to be performed by that concrete class, which you don't have yet, so you'll get a NullPointerException.
It's a sort of Chicken and Egg Problem! :)
I'm wondering what are the options to specialize generic types in Java, i.e. in a templated class to have specific overrides for certain types.
In my case I was a generic class (of type T) to return null usually, but return "" (the empty string), when T is the String type, or 0 (zero) when its the Integer type, etc.
Merely providing a type-specific overload of a method produces a "method is ambiguous" error:
e.g.:
public class Hacking {
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
Bar<String> barString = new Bar<String>();
// OK, returns null
System.out.println(barInt.get(new Integer(4)));
// ERROR: The method get(String) is ambiguous for the type Bar<String>
System.out.println(barString.get(new String("foo")));
}
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
}
Is the only option to subclass the generic class with a specific type (see StringBar in the following example?
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
StringBar barString2 = new StringBar();
// OK, returns null
System.out.println(barInt.get());
// OK, returns ""
System.out.println(barString2.get());
}
public static class Bar<T> {
public T get() {
return null;
}
}
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
}
Is this is the only way, it's a bit of a pain to have to create a subclass for every type I want to specialize instead of an overload of get() in the Bar class.
I'm guessing I could check the instanceof in the Bar.get() method, e.g.
T get(T t) {
if (t instanceof String) return "";
if (t instanceof Integer) return 0;
else return null;
}
However I've been taught to avoid instanceof and use polymorphism when possible.
All things considered, the concensus appears to be that the StringBar method mentioned in the question is the only way to go.
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
Generics in Java are very different from templates in C++ in this respect. It is not possible to write a specific version of a generic class to do something different for a particular case, as C++ can do. It is also not possible to determine at run time what T is - this is because that information is not passed into the byte code (object code) and so doesn't even exist at runtime. This due to something called "type erasure".
BarString and BarInt would be the obvious way of doing this, but there are improvements you can make. For example you can write a generic Bar to cover the common cases, and then write specialized BarString and BarInt to implement special cases. Ensure that the instances can only be created through a factory, which takes the class of the object to be processed:
class Bar<T> {
class BarString extends Bar<String> {
// specialist code goes here
}
static Bar<T> createBar(Class<T> clazz) {
if (clazz==String.class) {
return new BarString();
} else {
return new Bar<T>;
}
That probably won't compile, but I don't have the time to work out the exact syntax. It does illustrate the principle.
The compiler is actually correct, because the following code is compile-time checked (Bar<String> barString = new Bar<String>();) when compiled, from
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
to
public static class Bar<String> {
public String get(String x) {
return null;
}
public String get(String x) {
return "";
}
}
and is ambiguous as you can't have 2 identical methods with the same return types and the same parameter arguments.
See an explanation by Jon Skeet's:
What is the concept of erasure of generics in java?
Java Generics - Types erasures - when and what happens?
You can subclass Bar<T> and create StringBar (note I removed the static keyword) and override get() method.
public class BarString extends Bar<String> {
#Override
public String get(String x) {
return "";
}
}
Generics in Java aren't made for specialization. They're made for generalization! If you want to specialize for certain types, you should be specializing...through a subclass.
Often you don't need to do something in a specialized manner however. Your StringBar example is kind of contrived because you could have this:
public class Bar<T> {
private final T value;
public T get() {
return value;
}
}
I don't see why you need to specialize for a String here.