Objectify, Key<T> is it possible? Work arounds? - java

What I mean by type is something that would allow me to do the following.
public class AnyObject{
List<this.type> list;
}
I know the following dosen't work.
public class AnyObject{
List<this.getClass()> list;
}
So how would I create a lets say a list, for example sake, of type of whatever this is?
--------------- UPDATE ---------------
I apologize I don't think I was clear. I seem to be getting that there is no way to escape type erasure, but if there is still away to solve my problem I will explain it better. Disclosure, this is more of an Objectify question. Sorry I have come to see that now.
Here we go, clear as I can ...
For every entity I plan to persist, in GAE datastore using Objectiy, I would like to have a method to generate an Objectify Key<?> using the id and parent field. Lets call this method generateKey(). here is how it looks.
public Key<MyEntity> generateKey() {
Key<MyEntity> key = Key.create(this.parent, MyEntity.class, this.id);
return key;
}
The problem is I have to write this exact code, more or less, for every entity I create. Actually, there is other repeated code, but my point can be made with this piece of repeated code alone.
So I tried this. I created a class called MyProjectEntity and have all my entitys extend it. Then implemented a generateKey() method using generics.
public abstract class MyProjectEntity<T, Y> {
#Id Long id;
#Parent Key<T> parentKey;
public Key<Y> generateKey() {
Key<Y> key = Key.create(this.parentKey, this.getClass(), this.id);
return key;
}
}
Then I extended all my entity classes with this new class I created called MyProjectEntity. Like such ...
#Entity
public class MyEntity extends MyProjectEntity<MyEntityParent> {...}
Sounds good, now all my entity will have a generateKey() method, well this didn't quite work. Objectify yelled at me and said IllegalArgumentException, can not declare Key of type T.
Then I tried Key<Object>, Objectify was still unpleased, Objectify said Object is not a registered entity. Should I register Object!?!? and that kinda loses the whole point to a typed key that Objectify offers.
Is there a good solution. Thanks!
-- UPDATE 2 --
Since someone pointed out Key.create(myEntity) I should point my full use ...
/**********************************************************************************************************************
* Constructors END & Identification and Relationship Methods BEGIN
**********************************************************************************************************************/
#ApiSerializationProperty(name = "id")
public String getWebSafeKey() {
String webSafeKey = getKey().getString();
return webSafeKey;
}
public void setWebSafeKey(String webSafeKey) throws BadRequestException {
try {
Key<MyEntity> key = Key.create(webSafeKey);
setKey(key);
} catch (IllegalArgumentException illegalArgumentException) {
throw new BadRequestException(ErrorMessage.INVALID_ID);
}
}
#ApiSerializationProperty(name = "parentId")
public String getParentWebSafeKey() {
String webSafeKey = parent.getString();
return webSafeKey;
}
public void setParentWebSafeKey(String parentWebSafeKey) throws BadRequestException {
if (id == null) {
try {
parent = Key.create(parentWebSafeKey);
} catch (IllegalArgumentException illegalArgumentException) {
throw new BadRequestException(ErrorMessage.invalidParentId("Property"));
}
} else {
/* Do nothing. Only set parent here if setWebSafeKey is never called, such as during a create. */
}
}
#ApiSerializationProperty(ignored = AnnotationBoolean.TRUE)
public Key<MyEntity> getParentKey() {
return parent;
}
public void setParentKey(Key<MyEntity> parentKey) {
this.parent = parentKey;
}
#ApiSerializationProperty(ignored = AnnotationBoolean.TRUE)
public Key<MyEntity> getKey() {
Key<MyEntity> key = Key.create(parent, MyEntity.class, id);
return key;
}
public void setKey(Key<MyEntity> key) {
id = key.getId();
parent = key.getParent();
}
public boolean webSafeKeyEquals(String webSafeKey) {
boolean equals;
if (id !=null & parent !=null) {
equals = getWebSafeKey().equals(webSafeKey);
} else {
equals = false;
}
return equals;
}
/**********************************************************************************************************************
* Identification Methods END & Other Getters and Setters BEGIN
**********************************************************************************************************************/
All this has to be inserted for every entity I create with MyEntity replaced for the actual entity name. It's not just typing. This code doesn't belong in the entity class, but rather in some abstract parent. If I could have only code unique to a particular entity in the class, my model would be cleaner, and easier to expand. Thanks again.

This would not make sense. Consider: you would never know what the type of list is. Suppose that list is used in some method of some class, it could always be that this is an instance of a subclass. So the parameter of List in the type of list can never be assumed in any code. If it can never be known, then what is the point of it? You would just use List<?>.
Generics is a purely compile-time thing. Therefore, it is meaningless to depend on the runtime class of something.
I suggest that you have
public class AnyObject<T> {
List<T> list;
}
and any class Foo which wants to have list be a List<Foo>, for example, should just implement or inherit from AnyObject<Foo>.

This does not make sense List<this.getClass()> list; as the type parameters are compile time thing in java. This information is erased at runtime.

Without being familiar with Objectify, just generics, the thing I see is that Key.create is supposed to itself take a generic argument <T> for the type of returned Key. So you would be supposed to do the following when you call the method in the superclass:
Key<Y> key = Key.<Y>create(this.parentKey, this.getClass(), this.id);
You may only simply have to do that to fix the error (and should be doing it anyway). Otherwise Key.create will try to instantiate a new Key<Y> and although it is more or less valid to not declare a type argument when a method asks for one, apparently Key.create may not like that.
I think you should also take another look at your Ts and Ys because it appears you are mixing them. Right now you are handing Key.create a Key<T> as a parameter but wanting to return a Key<Y>. Also if you declare your class as having <T, Y> it should be illegal to extend it with only <MyEntityParent>.
Looking at your code I think what you are trying to do is create Key of the same class as the method you are calling it from. IE class generateKey in MyEntity should return a Key<MyEntity>. I think the proper way to do this would be like so (which is valid):
public abstract class MyProjectEntity<T, K> {
Long id;
Key<K> parentKey;
public Key<K> generateKey() {
return Key.<K>create(parentKey, this.getClass(), id);
}
}
public class MyEntity extends MyEntityParent<MyEntityParent, MyEntity> {
/*
* K is now MyEntity and parentKey is a Key<MyEntity>
* generateKey now does the following:
*
* public Key<MyEntity> generateKey() {
* return Key.<MyEntity>create(parentKey, MyEntity.class, id);
* }
*
*/
}
It just seems like your example that doesn't work is giving the error because you aren't declaring the types properly. But it is hard to tell because it is unclear what your T and Y are supposed to be. You only show one of the types being declared and at least in your generateKey method you are handing Key.create a Key<T> but wanting to return a Key<Y>.
Or perhaps you should take a look at Registering Entities in the Objectify API. IE it seems you might be supposed to do something like this and that is a possible reason you are getting the error:
static {
ObjectifyService.register(MyEntityParent.class);
}
But anyway in the world of Java generics you really ought to be able to do something like this without any gymnastics unless something else is going on. The nature of erasure is that you can't find out the type at runtime but the type is essentially "known" because all instances of T are replaced with the argument type.
public abstract class MyProjectEntity<T> {
Key<T> parentKey;
}
becomes
public class MyEntity extends MyProjectEntity<MyEntityParent> {
Key<MyEntityParent> parentKey;
}
You can't find out whether or not parentKey is of Type <MyEntityParent> but it is of that type. You can obviously see this with something like a java.util.List where if you do the following:
List<Double> doubleList = new ArrayList<Double>(0);
doubleList.add("a string");
You will get the following if you ignore the compiler errors and try to run the program anyway:
Uncompilable source code - Erroneous sym type: java.util.ArrayList.add
java.lang.RuntimeException: Uncompilable source code - Erroneous sym type: java.util.ArrayList.add
Because the list does "only hold" instances of Double. This situation could be compared to an anonymous class where that instance of an ArrayList's add method now officially takes a Double as an argument. It is uncompilable because I just tried to do this:
public void add(Double element) {
// add the element to the array
}
list.add("a string");
Which is obviously illegal. This ArrayList's underlying array is still an Object[] but the methods will be changed to reflect the type and safely make sure the array only holds Double elements at runtime.
So I would recommend taking a look at the things I mentioned because it appears that there's more than one problem unless you've omitted relevant code.

I think I understand your problem and here is how you could do it. The trick is to pass the subclass as a generic parameter of the parent class:
class Parent<T> {
T doStuff() {
T res = null;
// res = ..... this.getClass() is ok...
return res;
}
}
public class SelfGerenic extends Parent<SelfGerenic> {
}
public class OtherSubClass extends Parent<OtherSubClass> {
}

If I got you right, you're looking for something like this:
public class Test {
private int id;
public Key<Test> getKey() {
return createKey(id, this.getClass());
}
public static <T> Key<T> createKey(int id, Class<? extends T> clazz) {
return new Key<T>(clazz, id);
}
private static class Key<T> {
private final Class<? extends T> clazz;
private final int id;
private Key(Class<? extends T> clazz, int id) {
this.clazz = clazz;
this.id = id;
}
private int getId() {
return id;
}
private Class<? extends T> getClazz() {
return clazz;
}
}
public int getId() {
return id;
}
}
It is not possible to replace Test here: public Key<Test> getKey() {!
This is because getKey() always returns Key. It can not return Test.
So basically no, there is no way to change this behaviour. Also there is no way to get the generic type of the "current" class. This is some kind of limit of the java generics :P
You could remove the generics here, so you do not have to implement getKey() every time.
public class Test {
private int id;
public Key getKey() {
return createKey(id, this.getClass());
}
public static Key createKey(int id, Class clazz) {
return new Key(clazz, id);
}
private static class Key {
private final Class clazz;
private final int id;
private Key(Class clazz, int id) {
this.clazz = clazz;
this.id = id;
}
private int getId() {
return id;
}
private Class getClazz() {
return clazz;
}
}
public int getId() {
return id;
}
}

Related

How can I avoid an "Unchecked overriding" warning when interface method's generic return is implemented with a concrete type in Java?

This is an educational question that relates to a hobby project. Project Spring Boot MVC/REST app.
I would like to retain the flexibility to be able to create multiple implementations of Service and have list return a list of objects, depending on what the implementation requires.
I appreciate I could create some inheritance/implementation hierarchy to define the kinds of objects of which T could encompass. My problem with both of those answers is that some use cases for Service involve me needing to return Lists of Java Standard Lib types - types I would rather not inherit/extend/implement for my own custom classes, which I would prefer be kept as lean as possible.
import java.util.List;
interface Service {
<T> List<T> list(String location, MyEnums.mediaType type );
}
class MyEnums {
enum mediaType {
IMAGE, VIDEO, AUDIO
}
}
class LocalService implements Service {
public List<MyConcreteClass> list(String location, MyEnums.mediaType type ) {
List<MyConcreteClass> list = null;
list.add(new MyConcreteClass(1, "foo", new byte[0]));
return list;
}
}
class MyConcreteClass implements Comparable<MyConcreteClass> {
private final long id;
private final String name;
private final byte[] data;
public MyConcreteClass(long id, String name, byte[] data) {
this.id = id;
this.name = name;
this.data = data;
}
#Override
public int compareTo(MyConcreteClass o) {
return this.name.compareTo(o.name);
}
// Other methods omitted for brevity
}
The above code is only a simplified example of the actual app code - which compiles and runs without any (known) runtime bugs. However I get the compiler warning:
Unchecked overriding: return type requires unchecked conversion.
The presence of a warning makes sense to me - code consuming the Service interface/API could break at runtime if the return type requirement in the calling code is incompatible with the implementation, whereas the error would be caught at compile if I had a more specific List<> defined in the interface.
This would, of course, not be an issue if I had to wire in a concrete implementation into the code consuming my service - however the joys of Spring!
What am I doing wrong? How can I fix this? Are generics the right way to achieve a polymorphic list() function in my case?
You can eliminate the unchecked cast by declaring the interface itself with a type parameter (instead of the method). Like this:
interface Service<T> {
List<T> list(String location, String type );
}
class LocalService implements Service<MyConcreteClass> {
#Override
public List<MyConcreteClass> list(String location, String type ) {
// Some logic to retrieve, alter and return a list
return null;
}
}
class StringService implements Service<String> {
#Override
public List<String> list(String location, String type) {
// TODO Auto-generated method stub
return null;
}
}
class MyConcreteClass {
/// ...
}
(I changed a couple of things to make it compile, not relevant to the answer).

Getting Enum from an integer having a Class<? extends Enum> object

I have seen this which is pretty nice solution if i had a string instead of integer, but in case all i have is the specific enum's class object and an integer, how to do i get the specific enum constant instance?
Relying on the ordinal value of Java enum constants is poor practice -- it's too easy to accidentally reorder them, which would then break your code. The better solution is to simply provide your own integer that you can use instead:
public enum MyThing {
FOO(1),
BAR(2),
BAZ(3);
private final int thingId;
private MyThing(int thingId) {
this.thingId = thingId;
}
public int getThingId() {
return thingId;
}
}
Then whenever you want to get the thingId from a MyThing, just call the getThingId() method:
void doSomething(MyThing thing) {
System.out.printf("Got MyThing object %s with ID %d\n",
thing.name(), thing.getThingId());
}
If you want to be able to look up a MyThing by its thingId, you can build a lookup table yourself and store it in a static final field:
private static final Map<Integer, MyThing> LOOKUP
= createLookupMap();
private static Map<Integer, MyThing> createLookupMap() {
Map<Integer, MyThing> lookupMap = new HashMap<>();
for (MyThing thing : MyThing.values()) {
lookupMap.put(thing.getThingId(), thing);
}
return Collections.unmodifiableMap(lookupMap);
}
public static MyThing getThingById(int thingId) {
MyThing result = LOOKUP.get(thingId);
if (result == null) {
throw new IllegalArgumentException(
"This is not a valid thingId: " + thingId);
}
return result;
}
If you end up having a lot of enum classes and you want to do a similar thing with each of them, you can define an interface for that:
public interface Identifiable {
int getId();
}
And then make your enum implement that interface:
public enum MyThing implements Identifiable {
...
#Override
public int getId() {
return thingId;
}
}
And then you could build a reusable mechanism for looking up an Identifiable object based on its ID.
seem to have found the answer :
((Class<? extends Enum>)clazz).getEnumConstants()[index]
although for any-one looking for that, you should consider following #Daniel Pryden answer as most likely that using this in most use cases i can think of is bad practice.

Java, parent static method returning child type

I'm new to java and Generics so please bear with me. I don't even know if this is possible. I've looked around and although there seem to be a few posts about this here and there I haven't found one that addresses my specific case clearly enough for me to understand what to do.
I basically have a static method in the parent class and would like it to return various types based on which child calls it. The trick here is that said child class that is returned also needs to be instantiated within the method.
Here's what I mean:
public class Parent {
public String value;
public Parent(String value)
{
this.value = value;
}
public static <T extends Parent> T load(DataStorage data, String key)
{
T inst = new ???(data.getValue(key));
return inst;
}
}
public class Child extends Parent {
}
Child child = Child.load(dataStore, "key"); // random dataStore instance
I'm not sure where to go from here. What do I use in place of ??? which should be whichever child (or Parent) runs the load() ? Do I need to also do something along the lines of Child.<Child>load()?
I'm open to alternative designs if you feel I'm mistaking in trying to do things like this. I don't like the idea of having to play around with Reflection in this situation (feels a little hacky)
Thanks in advance, I really appreciate it.
I guess what you want would be possible if Java didn't have type erasure and had 'constructor with parameter constraint' for generic types(like .net, but it has constraint for parameterless constructors only).
Maybe those two suits your needs:
If type of Child based on some selection criteria(e.g. an enumaration) I would go with a factory pattern like:
public class ParentFactory {
Parent create(SomeEnum t, DataStore dataStore, String key) {
switch (t) {
case SomeEnum.Child1Related:
return new Child1(dataStore.get(key));
...
}
}
}
But if creation is completely irrelevant(which is not in most cases), you can just define an init method in Parent and have initializer code there:
abstract class Parent {
String value;
Parent() {}
protected void init(String s) { this.value = s; }
static <T extends Parent> void initialize(DataStore data, String key, T t) {
t.init(data.getValue(key));
}
Child c = new Child();
Parent.init(dataStore, key, c);
You can make init method as private if you want to prohibit childs to intercept that call.
Honestly, I favor first one much more. Second one is a little ugly :)
It sounds like the thing you're looking for is a strongly-typed key object, which can associate a string with the corresponding child type. What I've done in the past is simply write a class for this key type.
Assuming your datastore looks something like this:
public interface DataStore {
DataItem get(String key);
}
And your various child classes look like this:
public final class Child1 extends Parent {
public Child1(DataItem dataItem) {
...
}
...
}
Your Key type could look like this:
/**
* Represents a way to construct an object from a {#link DataItem}.
*
* #param <T> the type of the object to construct.
*/
public final class Key<T extends Parent> {
private final String key;
// Assuming Java 8 Function. If you're using Java 7 or older,
// you can define your own Function interface similarly.
private final Function<DataItem, T> factoryFunction;
public Key(String key, Function<String, T> factoryFunction) {
this.key = checkNotNull(key);
this.factoryFunction = checkNotNull(factoryFunction);
}
public String key() {
return this.key;
}
public T constructFrom(DataItem dataItem) {
if (!key.equals(dataItem.getKey())) {
throw new IllegalStateException(
"DataItem is not valid for key " + key);
}
return factoryFunction.apply(dataItem);
}
}
Then you'll probably want a collection of well-known keys:
/** Well-known {#link Key} instances. */
public final class Keys {
private Keys() {} // static class
/** Key for {#link Child1}. */
public static final Key<Child1> FIRST_CHILD
= new Key<>("child1", Child1::new);
/** Key for {#link Child2}. */
public static final Key<Child2> SECOND_CHILD
= new Key<>("child2", Child2::new);
// etc.
}
Then you can define classes that work with these strongly-typed key instances:
public final class Loader {
private final DataStore dataStore;
public Loader(DataStore dataStore) {
this.dataStore = checkNotNull(dataStore);
}
public <T extends Parent> T load(Key<T> dataKey) {
return key.constructFrom(dataStore.get(dataKey.key()));
}
...
}
Note that this example still works even if you don't have Java 8 -- you'll just need to use an anonymous inline class to construct the child, rather than a lambda expression:
public static final Key<Child1> FIRST_CHILD =
new Key<Child1>("child1", new Function<DataItem, Child1>() {
#Override public Child1 apply(DataItem dataItem) {
return new Child1(dataItem);
}
});
You could of course use reflection for this part if you want, but manually writing the supplier functions will be faster. (Or, if you want the best of both worlds, you could use something like cglib's FastClass.) If you wanted to, you could also make the Key class abstract, so that you would subclass it and override a factory method rather than using a Function.
If you want to, you can merge the Loader type into your Parent class, but I wouldn't, since I think that would violate the Single Responsibility Principle -- typically you want the job of loading domain objects from storage to be separate from the domain objects themselves.
Hopefully that helps!

Complicate generics in Java

I have one supertype defined as:
public abstract class AType<T> {
....
private T value;
private T mask;
public T getValue() {
if (isMasking())
return null;
return this.value;
}
public void setValue(T value) {
if (value == null)
throw new IllegalArgumentException("Value is mandatory.");
this.value = value;
}
protected T getMask() {
if (!isMasking())
return null;
return this.mask;
}
protected void setMask(T mask) {
if (mask == null)
throw new IllegalArgumentException("Mask is mandatory.");
this.setMasking(true);
this.mask = mask;
}
...
}
and few subtypes like:
public class SpecType extends AType<Integer> {
...
}
these sub types specifies the unknown parameter.... i have more f.e. IPv4, Long, and so on
now i need to somehow in runtime do a dynamic cast...
i have these classes defined in enum like this:
public enum Type {
SOME_TYPE(new TypeID(0, (short) 0), OFMU16.class,
new Instantiable<AType<?>>() {
#Override
public SpecType instantiate() {
return new SpecType(new OFMatchTypeIdentifier(0, (short) 0));
}
}),...;
...
public Class<? extends AType<?>> toClass() {
return this.clazz;
}
...
}
I want do something like:
AType<?> type = SOME_TYPE.newInstance(); //this works
SOME_TYPE.toClass().cast(type).setValue(10); //this don't work
so I have to do it statically:
((SpecType) type).setValue(10);
Everything would be OK, but the user of this module will not want to look in enum and cast manually every time. This will probably make mistakes and spend a lot of time with debugging :/....
My question is how can I refactor this or how do I define structure of inheritance to allow user to cast dynamically? Is it possible?
Edit:
I am parsing packets from network. There is a lot types which differs in Vendor Type identifier and type of Value/Mask - these fields are all constant for every this combination, so i has defined it as enum constants. F.e. 20 have different only TypeID but same VendorID and all of them can be represented as Integer, next 10 differ in VendorID And TypeID but all of them can be represented as Short and so on.
It's still not clear why you should have to cast at all. As soon as SOME_TYPE is written into your sourcecode OR the type of set setValue method is hardcoded (in your example int or Integer) you don't need runtime checking - you need compile time checking.
So I suppose the following snippet is how your API users should code:
public class TypeTest {
public static void main(String[] args) {
AType<Integer> type0 = Types.SOME_TYPE_0.instantiate();
type0.setValue(10);
AType<String> type1 = Types.SOME_TYPE_1.instantiate();
type1.setValue("foo");
}
}
I have stripped down your example to the bare minimum which is required to understand the Generics part:
abstract class AType<T> {
private T value;
// standard getter/setter
public T getValue() { return this.value; }
public void setValue(T value) { this.value = value; }
}
class SpecTypeInt extends AType<Integer> {
}
class SpecTypeString extends AType<String> {
}
interface Instantiable<T> {
T instantiate();
}
The key part is: Don't use an enum, because an enum cannot have type parameters. You can use a plain interface instead like the next snippet. Each reference in the interface points to a factory. Each factory knows a) the abstract type and b) the concrete type. To make Generics happy you have to glue a) and b) together with ? extends X.
interface Types {
Instantiable<? extends AType<Integer>> SOME_TYPE_0 = new Instantiable<SpecTypeInt>() {
#Override
public SpecTypeInt instantiate() {
return new SpecTypeInt();
}
};
Instantiable<? extends AType<String>> SOME_TYPE_1 = new Instantiable<SpecTypeString>() {
#Override
public SpecTypeString instantiate() {
return new SpecTypeString();
}
} ;
}
Cleanup: Must your user look into the interface: Yes, he must in any case, because he must know which is the appropriate type for setValue 1. NO solution can circumvent this. Although Eclipse might help you and your users a little bit: In main just type Types.SOME_TYPE_1.instantiate(); then go to the start of the line, hit Ctrl2 + L ("Assign to loccal variable") and Eclipse replaces the AType<String> instantiate = part for you.
1If your users don't know the right type for the setValue method, then you are asking the wrong question. In that case you should have asked something like "How to design a Generic safe conversion facility?".
Maybe using a setValue method like this:
public void setValue(Object value) {
if (value == null)
throw new IllegalArgumentException("Value is mandatory.");
this.value = (T)value;
}
Although you will have an unchecked cast.
Hope this helps

How can I eliminate duplicated Enum code?

I have a large number of Enums that implement this interface:
/**
* Interface for an enumeration, each element of which can be uniquely identified by its code
*/
public interface CodableEnum {
/**
* Get the element with a particular code
* #param code
* #return
*/
public CodableEnum getByCode(String code);
/**
* Get the code that identifies an element of the enum
* #return
*/
public String getCode();
}
A typical example is:
public enum IMType implements CodableEnum {
MSN_MESSENGER("msn_messenger"),
GOOGLE_TALK("google_talk"),
SKYPE("skype"),
YAHOO_MESSENGER("yahoo_messenger");
private final String code;
IMType (String code) {
this.code = code;
}
public String getCode() {
return code;
}
public IMType getByCode(String code) {
for (IMType e : IMType.values()) {
if (e.getCode().equalsIgnoreCase(code)) {
return e;
}
}
}
}
As you can imagine these methods are virtually identical in all implementations of CodableEnum. I would like to eliminate this duplication, but frankly don't know how. I tried using a class such as the following:
public abstract class DefaultCodableEnum implements CodableEnum {
private final String code;
DefaultCodableEnum(String code) {
this.code = code;
}
public String getCode() {
return this.code;
}
public abstract CodableEnum getByCode(String code);
}
But this turns out to be fairly useless because:
An enum cannot extend a class
Elements of an enum (SKYPE, GOOGLE_TALK, etc.) cannot extend a class
I cannot provide a default implementation of getByCode(), because DefaultCodableEnum is not itself an Enum. I tried changing DefaultCodableEnum to extend java.lang.Enum, but this doesn't appear to be allowed.
Any suggestions that do not rely on reflection?
Thanks,
Don
You could factor the duplicated code into a CodeableEnumHelper class:
public class CodeableEnumHelper {
public static CodeableEnum getByCode(String code, CodeableEnum[] values) {
for (CodeableEnum e : values) {
if (e.getCode().equalsIgnoreCase(code)) {
return e;
}
}
return null;
}
}
Each CodeableEnum class would still have to implement a getByCode method, but the actual implementation of the method has at least been centralized to a single place.
public enum IMType implements CodeableEnum {
...
public IMType getByCode(String code) {
return (IMType)CodeableEnumHelper.getByCode(code, this.values());
}
}
Abstract enums are potentially very useful (and currently not allowed). But a proposal and prototype exists if you'd like to lobby someone in Sun to add it:
http://freddy33.blogspot.com/2007/11/abstract-enum-ricky-carlson-way.html
Sun RFE:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6570766
To tidy up dave's code:
public class CodeableEnumHelper {
public static <E extends CodeableEnum> E getByCode(
String code, E[] values
) {
for (E e : values) {
if (e.getCode().equalsIgnoreCase(code)) {
return e;
}
}
return null;
}
}
public enum IMType implements CodableEnum {
...
public IMType getByCode(String code) {
return CodeableEnumHelper.getByCode(code, values());
}
}
Or more efficiently:
public class CodeableEnumHelper {
public static <E extends CodeableEnum> Map<String,E> mapByCode(
E[] values
) {
Map<String,E> map = new HashMap<String,E>();
for (E e : values) {
map.put(e.getCode().toLowerCase(Locale.ROOT), value) {
}
return map;
}
}
public enum IMType implements CodableEnum {
...
private static final Map<String,IMType> byCode =
CodeableEnumHelper.mapByCode(values());
public IMType getByCode(String code) {
return byCode.get(code.toLowerCase(Locale.ROOT));
}
}
I had a similar issue with a localization component that I wrote. My component is designed to access localized messages with enum constants that index into a resource bundle, not a hard problem.
I found that I was copying and pasting the same "template" enum code all over the place. My solution to avoid the duplication is a code generator that accepts an XML configuration file with the enum constant names and constructor args. The output is the Java source code with the "duplicated" behaviors.
Now, I maintain the configuration files and the generator, not all of the duplicated code. Everywhere I would have had enum source code, there is now an XML config file. My build scripts detect out-of-date generated files and invoke the code generator to create the enum code.
You can see this component here. The template that I was copying and pasting is factored out into an XSLT stylesheet. The code generator runs the stylesheet transformation. An input file is quite concise compared to the generated enum source code.
HTH,
Greg
Unfortunately, I don't think that there is a way to do this. Your best bet would pro ably be to give up in emums altogether and use conventional class extension and static members. Otherwise, get used to duplicating that code. Sorry.
Create a type-safe utility class which will load enums by code:
The interface comes down to:
public interface CodeableEnum {
String getCode();
}
The utility class is:
import java.lang.reflect.InvocationTargetException;
public class CodeableEnumUtils {
#SuppressWarnings("unchecked")
public static <T extends CodeableEnum> T getByCode(String code, Class<T> enumClass) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
T[] allValues = (T[]) enumClass.getMethod("values", new Class[0]).invoke(null, new Object[0]);
for (T value : allValues) {
if (value.getCode().equals(code)) {
return value;
}
}
return null;
}
}
A test case demonstrating usage:
import junit.framework.TestCase;
public class CodeableEnumUtilsTest extends TestCase {
public void testWorks() throws Exception {
assertEquals(A.ONE, CodeableEnumUtils.getByCode("one", A.class));
assertEquals(null, CodeableEnumUtils.getByCode("blah", A.class));
}
enum A implements CodeableEnum {
ONE("one"), TWO("two"), THREE("three");
private String code;
private A(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
}
Now you are only duplicating the getCode() method and the getByCode() method is in one place. It might be nice to wrap all the exceptions in a single RuntimeException too :)
Here I have another solution:
interface EnumTypeIF {
String getValue();
EnumTypeIF fromValue(final String theValue);
EnumTypeIF[] getValues();
class FromValue {
private FromValue() {
}
public static EnumTypeIF valueOf(final String theValue, EnumTypeIF theEnumClass) {
for (EnumTypeIF c : theEnumClass.getValues()) {
if (c.getValue().equals(theValue)) {
return c;
}
}
throw new IllegalArgumentException(theValue);
}
}
The trick is that the inner class can be used to hold "global methods".
Worked pretty fine for me. OK, you have to implement 3 Methods, but those methods,
are just delegators.
It seems like you are actually implementing run time type information. Java provides this as a language feature.
I suggest you look up RTTI or reflection.
I don't think this is possible. However, you could use the enum's valueOf(String name) method if you were going to use the enum value's name as your code.
How about a static generic method? You could reuse it from within your enum's getByCode() methods or simply use it directly. I always user integer ids for my enums, so my getById() method only has do do this: return values()[id]. It's a lot faster and simpler.
If you really want inheritance, don't forget that you can implement the enum pattern yourself, like in the bad old Java 1.4 days.
About as close as I got to what you want was to create a template in IntelliJ that would 'implement' the generic code (using enum's valueOf(String name)). Not perfect but works quite well.
In your specific case, the getCode() / getByCode(String code) methods seems very closed (euphemistically speaking) to the behaviour of the toString() / valueOf(String value) methods provided by all enumeration. Why don't you want to use them?
Another solution would be not to put anything into the enum itself, and just provide a bi-directional map Enum <-> Code for each enum. You could e.g. use ImmutableBiMap from Google Collections for this.
That way there no duplicate code at all.
Example:
public enum MYENUM{
VAL1,VAL2,VAL3;
}
/** Map MYENUM to its ID */
public static final ImmutableBiMap<MYENUM, Integer> MYENUM_TO_ID =
new ImmutableBiMap.Builder<MYENUM, Integer>().
put(MYENUM.VAL1, 1).
put(MYENUM.VAL2, 2).
put(MYENUM.VAL3, 3).
build();
In my opinion, this would be the easiest way, without reflection and without adding any extra wrapper to your enum.
You create an interface that your enum implements:
public interface EnumWithId {
public int getId();
}
Then in a helper class you just create a method like this one:
public <T extends EnumWithId> T getById(Class<T> enumClass, int id) {
T[] values = enumClass.getEnumConstants();
if (values != null) {
for (T enumConst : values) {
if (enumConst.getId() == id) {
return enumConst;
}
}
}
return null;
}
This method could be then used like this:
MyUtil.getInstance().getById(MyEnum.class, myEnumId);

Categories

Resources