Working with <key, value> enums in a clean way - java

I'm looking for ways to implement and access my enum and I'm not very happy with how nice the code looks. It seems like a patched way. So here is what I'm trying to do:
Consider this simple enum as an example of what I'm trying to do:
public enum MyEnum {
FIRST(0L), SECOND(1L), THIRD(2L);
private Long number;
private MyEnum(Long number){
this.number= id;
}
public static boolean isFirst(MyEnum type) {
return type == FIRST;
}
public static boolean isSecond(MyEnum type) {
return type == SECOND;
}
public static boolean isThird(MyEnum type) {
return type == THIRD;
}
public Long getId() {
return number;
}
}
Later on, I have some objects that I set as Long.valueOf(1L), and compare them with this enum using
Long.valueOf(1L).equals(instanceOfMyEnum.getId())
I really hate having those hardcoded constants all over my code so I was wondering if it's a bad practice to use something like this instead:
eMyEnum.FIRST.getId().equals(instanceOfMyEnum.getId())
or
someLongThatIPassAsParameter = eMyEnum.FIRST.getId();
These are just some simple examples but basically it's the same problem repeated over and over. What do you think?

If you have a lots of enum values, i would do something like this (No need to modify the code if you add new ones):
public enum MyEnum {
FIRST(0L), SECOND(1L), THIRD(2L);
private Long number;
/**
* Lookup map, to provide a quick way to access your enums by id
*/
private static final Map<Long, MyEnum> LOOKUP = new HashMap<Long, MyEnum>();
/**
* Static initializer, which loads your enums values runtime, and maps them
* to their 'number' member.
*/
static {
MyEnum[] enums = MyEnum.class.getEnumConstants();
for(MyEnum en : enums){
LOOKUP.put(en.number, en);
}
}
private MyEnum(final Long number) {
this.number = number;
}
/**
* Gets the enum value associated with the parameter, id.
* #param id The id, that identifies your enum value
* #return The enum value, or null, if not found.
*/
public static MyEnum getById(final Long id){
return LOOKUP.get(id);
}
}

Im not sure if I understood your question correctly, but what about using switch for the checks this for the checks?
public enum MyEnum {
FIRST(0L), SECOND(1L), THIRD(2L);
private Long number;
private static Map<Long, MyEnum> byIds = new HashMap<Long, PlaceServiceV2.MyEnum>();
static{
for(MyEnum myEnum :MyEnum.values()){
byIds.put(myEnum.number, myEnum);
}
}
private MyEnum(Long number){
this.number = number;
}
public static MyEnum getById(Long id) {
return byIds.get(id);
}
public Long getId() {
return number;
}
}
public void test(){
switch (MyEnum.getById(1L)) {
case FIRST:
break;
case SECOND:
break;
default:
break;
}
}

Why not implement a fromLong method in the enum
public static MyEnum fromLong(long l) {
switch (l) {
{
case 0: return FIRST;
case 1: return SECOND;
case 2: return THIRD;
}
throw new IllegalArgumentException();
}
and then convert longs to the enum and compare enums. So you would have:
MyEnum.fromLong(longValue) == MyEnum.FIRST

Apparently although you created an enum, your are still using these Long values everywhere, so maybe you can just use something like:
public class TypeOfSomething {
public static final long FIRST = 1l;
public static final long ANALOG = 2l;
public static final long USB = 3l;
}
and then use them like:
someLongThatIPassAsParameter = TypeOfSomething.ANALOG;
enum way is also fine, but I use it in case where it is more comfortable to use enum values in parameters, and value within enum is just additional information (e.g. messages.properties keys for internationalisation)

Related

How to nest enum

I have some UI client filters (combobox and checkbox group) that I need to use on server side: I thought to use an enum to identify filter types and others enums to identify each filter's options.
// All UI filters
public enum FilterType {
AGGREGATION("aggregation"),
AREA("area"),
PRODUCTION("production"),
DATA_TYPE("datatype"),
PRODUCER("producer"),
NETWORK("network"),
SOURCE("source");
private String value;
private FilterType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
// FilterType.AGGREGATION filter options
public enum AggregationOptionType {
STANDARD("standard"),
DTR("dtr"),
CO("co");
private String value;
private AggregationOptionType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
I would like to craete a hard link between FilterType.AGGREGATION and AggregationOptionType forcing the access to an option via FilterType.AGGREGATION.DTR.
How can I "nest" an enum inside a value of another enum?
Are there other patterns (maybe smarter than mine) to achieve the same result?
EDIT
A clarification: I do NOT need to assign to each value of the outer enum a value of a common inner enum. I need to assign a whole different inner enum to each value of the outer enum.
You can put one enum into another, like:
enum OuterEnum {
A, B;
enum InnerEnum {
C, D;
}
}
To use like:
class Enumuser {
OuterEnum.InnerEnum ie = OuterEnum.InnerEnum.C;
}
But of course, that is not exactly what you are looking for.
You need to go one step further:
enum OuterEnum {
A(InnerEnum.C), B(InnerEnum.D);
private final InnerEnum inner;
private OuterEnum(InnerEnum inner) { this.inner = inner; }
public InnerEnum getInner() { return inner; }
enum InnerEnum {
C, D;
}
}
class Enumuser {
OuterEnum.InnerEnum inner = OuterEnum.A.getInner();
}
But a final word of warning: don't get too hang up on using enums for such purposes. You see, as soon as you start writing switch statements all over the place that switch over such enums, in order to do this or that ... you are probably doing something wrong. Consider not "falling into that enum trap" please.
Instead you should be looking into using polymorphism, like shown here!
You can add it to the Enum, as a variable.
But only if you can have all the sub Enums under the same enum type ie
public enum FilterType {
AGGREGATION("aggregation",Subfilter.DTR);
}
You can do something like as follows:
//All UI filters
public interface FilterType {
// FilterType.AGGREGATION
public interface AGGREGATION {
// FilterType.AGGREGATION filter options
enum AggregationOptionType {
STANDARD("standard"),
DTR("dtr"),
CO("co");
private String value;
private AggregationOptionType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
}
}
e.g. for AGGREGATION
Just use it in the same way like a String value and if you want to have a single file, so hold your enums in a interface class:
public interface Enums {
public enum FilterType {
AGGREGATION("aggregation", AggregationOptionType.DTR),
AREA("area"),
PRODUCTION("production"),
DATA_TYPE("datatype"),
PRODUCER("producer"),
NETWORK("network", AggregationOptionType.CO),
SOURCE("source");
public final String value;
public final AggregationOptionType type;
private FilterType(String value, AggregationOptionType typy) {
this.value = value;
this.type = typy;
}
private FilterType(String value) {
this.value = value;
this.type = AggregationOptionType.STANDARD;
}
}
public enum AggregationOptionType {
STANDARD("standard"),
DTR("dtr"),
CO("co");
public final String value;
private AggregationOptionType(String value) {
this.value = value;
}
}
}

Good way to organize group of constants in enum-like fashion

I'm trying to find a good way to orginize a group of constant values that are used simply for immutable data.
Here is what I'm currently attempting:
public class FishType {
//PredatorFishType extends FishType
public static final PredatorFishType SHARK = new PredatorFishType(5, 20, "Shark");
public static final FishType CAT_FISH = new FishType("Cat Fish");
private String name;
private FishType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
I use reflection to gather the final values into a collection aswell. I used to utilize enum but was forced to think of a new way to do this when different types of fish came into play such as the predator which contains other data such as food and so on. These constants are only used for data displaying purposes and have no reason to be mutated.
If there is some way to have multiple enum types within the same enum (If that makes any sense at all), that'd be great.
Thanks for reading.
You can either use constructor overloading or a combination of overloading and a wrapper class. If you know for certain that this data is immutable and will always be that way, I don't see anything wrong with sticking to enums for it. For the sake of putting it into one class, I've included the enums in the EnumTester class, but you may not want to do that.
Here's an example that prints "Cat Fish 5 20 Shark" and "Cow Fish" when run, using nothing but enums and a wrapper class. You could put accessors wherever you need them, depending on what you actually want to do with the information - I'm trying to demonstrate how to compose the two enums, not how to use them.
package enums;
public class EnumTester
{
public enum MainType {
CAT_FISH("Cat Fish"), DOG_FISH("Dog Fish"), COW_FISH("Cow Fish"); //everything has a name...
private String name;
private MainType(String name){
this.name = name;
}
public String getTypeDetails(){
return name;
}
}
public enum SubType {
PREDATOR(5, 20, "Shark"), PREY(), MANATEE(); //but not everything has any additional information
private boolean isFullSubType;
private int val1;
private int val2;
private String subName;
private SubType(int val1, int val2, String subName){
this.isFullSubType = true;
this.val1 = val1;
this.val2 = val2;
this.subName = subName;
}
private SubType(){
this.isFullSubType = false;
this.val1 = -1;
this.val2 = -1;
this.subName = "none";
}
public String getSubTypeDetails()
{
if( isFullSubType ) {
return val1 + " " + val2 + " " + subName;
}
else {
return "";
}
}
}
private MainType mainType;
private SubType subType;
public EnumTester(MainType mainType, SubType subType)
{
this.mainType = mainType;
this.subType = subType;
}
public static void main(String[] args)
{
EnumTester kittyShark = new EnumTester(MainType.CAT_FISH, SubType.PREDATOR);
System.out.println(kittyShark.printDetails());
EnumTester cowManatee = new EnumTester(MainType.COW_FISH, SubType.MANATEE);
System.out.println(cowManatee.printDetails());
}
public String printDetails(){
return mainType.getTypeDetails()+" "+subType.getSubTypeDetails();
}
}
I typically follow a similar pattern to what you've done above. I might make the class FishTypes to be the collector, just to keep the FishType interface a bit cleaner. You can also invent some syntactic sugar to help you collect registered FishTypes:
public static final Set<FishType> registeredFish = new HashSet<>();
public static final PredatorFishType SHARK = register(new PredatorFishType(5, 20, "Shark"));
public static final FishType CAT_FISH = register(new FishType("Cat Fish"));
public static <T extends FishType> T register(T fishType) {
registeredFish.add(fishType);
return fishType;
}

Enum versus lookup table

I'm implementing a solution in Java using Ebean and I'm having some issues choosing between using Enums or simply look up tables.
I have a table "Tooth". A tooth can be "Temporary" or "Permanent".
I could create a simple Enum:
#EnumMapping(nameValuePairs = "TEMPORARY=T, PERMANENT=P")
public enum DentitionType { TEMPORARY, PERMANENT; }
However if I want to do a direct SQL query I have to convert "T" and "P", so a solution would be to use a lookup table as below:
#Entity
public class DentitionType {
#Column(length = 15)
public String name;
private static DentitionType permanent;
public boolean isTemporary() {
return !this.equals(getPermanent());
}
public boolean isPermanent() {
return this.equals(getPermanent());
}
public static DentitionType getPermanent() {
if (permanent == null) {
permanent = DentitionType.FIND.byId(2L);
}
return permanent;
}
}
This feels kind of hardcoded and for larger tables a lot of isSomething functions are required.
Is there a better solution? Thanks in advance.
Why do you not use?
public enum DentitionType {
TEMPORARY('T'), PERMANENT('P');
private char value;
private Currency(char value) {
this.value = value;
}
public static DentitionType Get(final char value){
for (DentitionType type : DentitionType.values())
if (type.name == name)
return type;
return null;
}
};

Are there any advantages between List<CustomObject> and HashMap <String, Object>

I am trying to implement a solution (in Java 1.6) where i need to store some values (for a set of properties) and thinking in three options considering the following three (Any other idea is of course wellcome!)
Option 1
Create a class (call it Property) that can store different type of objects (String, int, boolean...) and and work with the set of properties as a List<Property>
Something like:
private String type; //Store the type of Object
private String name; //Store the name of the property
private String valueStr; //Store the String value
private int valueInt; //Store the int value
private boolean valueBool; //Store the boolean value
I dont really like the idea of having many properties and using only one of them. (only one of the values will be set per property)
Option 2
Use HashMap<String, Object> and parse the type on each case.
Have the good thing that you can get the Property by name
Option 3
Use HashMap<String, Property> Where the String is the name of the property and you can get the value with the name and no need to parse.
Questions are:
Which of one you think is the best one?
or if none of them are good i would like to hear other ideas
Also is there any performance difference between the List and the HashMap?
Thanks in advance for the help.
I think better is to have a custom Value class like this:
public class MyValue {
enum Type {
INT, STRING, BOOL;
}
private Type type; //Store the type of Object in Type Enum
private Object value; //Store the value in Object
public void setValue(int val) {
type = Type.INT;
value = new Integer(val);
}
public void setValue(String val) {
type = Type.STRING;
value = val;
}
public void setValue(boolean val) {
type = Type.BOOL;
value = new Boolean(val);
}
public String stringVal() {
// check type to be STRING first
return (String) value;
}
public int intVal() {
// check type to be INT first
return ((Integer) value.intValue());
}
public boolean booleanVal() {
// check type to be BOOL first
return ((Boolean) value.booleanValue());
}
}
You will need to convert from Object to specific type based on enum Type in your getters.
Another option would be something like this, using inheritance rather than keeping a large number of unused fields around.
public interface Property {
String getType();
String getName();
Object getValue();
}
public abstract class AbstractProperty implements Property {
private final String name;
protected AbstractProperty(String name) {
this.name = name;
}
}
public class StringProperty extends AbstractProperty {
private final String value;
public StringProperty(String name, String value) {
super(name);
this.value = value;
}
#Override
public String getType() {
return String.class.getName();
}
#Override
public String getValue() {
return value;
}
}
public class IntegerProperty extends AbstractProperty {
private final Integer value;
public IntegerProperty(String name, Integer value) {
super(name);
this.value = value;
}
#Override
public String getType() {
return Integer.TYPE.getName();
}
#Override
public Integer getValue() {
return value;
}
}
I think option 2 would be the best for you. Considering that you are storing properties I am expecting that you would be querying this list quite often which again points in the direction of a HashMap as that would make your lookup very efficient.
I suggest using an enum instead. Enums are good for holding lists of values, and are effective at retrieval.
public enum Property {
TYPE,
NAME,
VALUEINT; //...
private String sProp = "";
private int iProp = 0;
private boolean bProp = false;
public String getStringProp() {return sProp;}
public int getIntProp() {return iProp;}
public boolean getBoolProp() {return bProp;}
public void setStringProp(String str) {this.sProp = str;}
public void setIntProp(int i) {this.iProp = i;}
public void setBoolProp(boolean b) {this.bProp = b;}
}
This can then be accessed with Property.TYPE, Property.VALUEINT, etc. You can set properties with Property.TYPE.setStringProp(), and get them with Property.TYPE.getStringProp().
You can read more about enums from Oracle's site.
I am unsure if there's one 'best' way. It really depends on how the data would be used after storing in a data structure.
In cases when I just need to accumulate properties and do something on each of them, I'd use a list, or even an array, sometimes.
If you might have to get a particular property, say by name, then a HashMap could help.
Again if you want to use the native object type or an instance of Property depends on what kind of data you have.
Which performs better depends on the number of objects you have, how you'd access them for use, how often you'd insert and several other factors.

Conveniently map between enum and int / String

When working with variables/parameters that can only take a finite number of values, I try to always use Java's enum, as in
public enum BonusType {
MONTHLY, YEARLY, ONE_OFF
}
As long as I stay inside my code, that works fine. However, I often need to interface with other code that uses plain int (or String) values for the same purpose, or I need to read/write from/to a database where the data is stored as a number or string.
In that case, I'd like to have a convenient way to associate each enum value with a an integer, such that I can convert both ways (in other words, I need a "reversible enum").
Going from enum to int is easy:
public enum BonusType {
public final int id;
BonusType(int id) {
this.id = id;
}
MONTHLY(1), YEARLY(2), ONE_OFF(3);
}
Then I can access the int value as BonusType x = MONTHLY; int id = x.id;.
However, I can see no nice way for the reverse, i.e. going from int to enum. Ideally, something like
BonusType bt = BonusType.getById(2);
The only solutions I could come up with are:
Put a lookup method into the enum, which uses BonusType.values() to fill a map "int -> enum", then caches that and uses it for lookups. Would work, but I'd have to copy this method identically into each enum I use :-(.
Put the lookup method into a static utility class. Then I'd only need one "lookup" method, but I'd have to fiddle with reflection to get it to work for an arbitrary enum.
Both methods seem terribly awkward for such a simple (?) problem.
Any other ideas/insights?
enum → int
yourEnum.ordinal()
int → enum
EnumType.values()[someInt]
String → enum
EnumType.valueOf(yourString)
enum → String
yourEnum.name()
A side-note:As you correctly point out, the ordinal() may be "unstable" from version to version. This is the exact reason why I always store constants as strings in my databases. (Actually, when using MySql, I store them as MySql enums!)
http://www.javaspecialists.co.za/archive/Issue113.html
The solution starts out similar to yours with an int value as part of the enum definition. He then goes on to create a generics-based lookup utility:
public class ReverseEnumMap<V extends Enum<V> & EnumConverter> {
private Map<Byte, V> map = new HashMap<Byte, V>();
public ReverseEnumMap(Class<V> valueType) {
for (V v : valueType.getEnumConstants()) {
map.put(v.convert(), v);
}
}
public V get(byte num) {
return map.get(num);
}
}
This solution is nice and doesn't require 'fiddling with reflection' because it's based on the fact that all enum types implicitly inherit the Enum interface.
I found this on the web, it was very helpful and simple to implement.
This solution was NOT made by me
http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks
public enum Status {
WAITING(0),
READY(1),
SKIPPED(-1),
COMPLETED(5);
private static final Map<Integer,Status> lookup
= new HashMap<Integer,Status>();
static {
for(Status s : EnumSet.allOf(Status.class))
lookup.put(s.getCode(), s);
}
private int code;
private Status(int code) {
this.code = code;
}
public int getCode() { return code; }
public static Status get(int code) {
return lookup.get(code);
}
}
Seems the answer(s) to this question are outdated with the release of Java 8.
Don't use ordinal as ordinal is unstable if persisted outside the
JVM such as a database.
It is relatively easy to create a static map
with the key values.
public enum AccessLevel {
PRIVATE("private", 0),
PUBLIC("public", 1),
DEFAULT("default", 2);
AccessLevel(final String name, final int value) {
this.name = name;
this.value = value;
}
private final String name;
private final int value;
public String getName() {
return name;
}
public int getValue() {
return value;
}
static final Map<String, AccessLevel> names = Arrays.stream(AccessLevel.values())
.collect(Collectors.toMap(AccessLevel::getName, Function.identity()));
static final Map<Integer, AccessLevel> values = Arrays.stream(AccessLevel.values())
.collect(Collectors.toMap(AccessLevel::getValue, Function.identity()));
public static AccessLevel fromName(final String name) {
return names.get(name);
}
public static AccessLevel fromValue(final int value) {
return values.get(value);
}
}
org.apache.commons.lang.enums.ValuedEnum;
To save me writing loads of boilerplate code or duplicating code for each Enum, I used Apache Commons Lang's ValuedEnum instead.
Definition:
public class NRPEPacketType extends ValuedEnum {
public static final NRPEPacketType TYPE_QUERY = new NRPEPacketType( "TYPE_QUERY", 1);
public static final NRPEPacketType TYPE_RESPONSE = new NRPEPacketType( "TYPE_RESPONSE", 2);
protected NRPEPacketType(String name, int value) {
super(name, value);
}
}
Usage:
int -> ValuedEnum:
NRPEPacketType packetType =
(NRPEPacketType) EnumUtils.getEnum(NRPEPacketType.class, 1);
You could perhaps use something like
interface EnumWithId {
public int getId();
}
enum Foo implements EnumWithId {
...
}
That would reduce the need for reflection in your utility class.
In this code, for permanent and intense search , have memory or process for use, and I select memory, with converter array as index.
I hope it's helpful
public enum Test{
VALUE_ONE(101, "Im value one"),
VALUE_TWO(215, "Im value two");
private final int number;
private final byte[] desc;
private final static int[] converter = new int[216];
static{
Test[] st = values();
for(int i=0;i<st.length;i++){
cv[st[i].number]=i;
}
}
Test(int value, byte[] description) {
this.number = value;
this.desc = description;
}
public int value() {
return this.number;
}
public byte[] description(){
return this.desc;
}
public static String description(int value) {
return values()[converter[rps]].desc;
}
public static Test fromValue(int value){
return values()[converter[rps]];
}
}
Use an interface to show it who's boss.
public interface SleskeEnum {
int id();
SleskeEnum[] getValues();
}
public enum BonusType implements SleskeEnum {
MONTHLY(1), YEARLY(2), ONE_OFF(3);
public final int id;
BonusType(int id) {
this.id = id;
}
public SleskeEnum[] getValues() {
return values();
}
public int id() { return id; }
}
public class Utils {
public static SleskeEnum getById(SleskeEnum type, int id) {
for(SleskeEnum t : type.getValues())
if(t.id() == id) return t;
throw new IllegalArgumentException("BonusType does not accept id " + id);
}
public static void main(String[] args) {
BonusType shouldBeMonthly = (BonusType)getById(BonusType.MONTHLY,1);
System.out.println(shouldBeMonthly == BonusType.MONTHLY);
BonusType shouldBeMonthly2 = (BonusType)getById(BonusType.MONTHLY,1);
System.out.println(shouldBeMonthly2 == BonusType.YEARLY);
BonusType shouldBeYearly = (BonusType)getById(BonusType.MONTHLY,2);
System.out.println(shouldBeYearly == BonusType.YEARLY);
BonusType shouldBeOneOff = (BonusType)getById(BonusType.MONTHLY,3);
System.out.println(shouldBeOneOff == BonusType.ONE_OFF);
BonusType shouldException = (BonusType)getById(BonusType.MONTHLY,4);
}
}
And the result:
C:\Documents and Settings\user\My Documents>java Utils
true
false
true
true
Exception in thread "main" java.lang.IllegalArgumentException: BonusType does not accept id 4
at Utils.getById(Utils.java:6)
at Utils.main(Utils.java:23)
C:\Documents and Settings\user\My Documents>
Both the .ordinal() and values()[i] are unstable since they are dependent to the order of enums. Thus if you change the order of enums or add/delete some your program would break.
Here is a simple yet effective method to map between enum and int.
public enum Action {
ROTATE_RIGHT(0), ROTATE_LEFT(1), RIGHT(2), LEFT(3), UP(4), DOWN(5);
public final int id;
Action(int id) {
this.id = id;
}
public static Action get(int id){
for (Action a: Action.values()) {
if (a.id == id)
return a;
}
throw new IllegalArgumentException("Invalid id");
}
}
Applying it for strings shouldn't be difficult.
A very clean usage example of reverse Enum
Step 1
Define an interface EnumConverter
public interface EnumConverter <E extends Enum<E> & EnumConverter<E>> {
public String convert();
E convert(String pKey);
}
Step 2
Create a class name ReverseEnumMap
import java.util.HashMap;
import java.util.Map;
public class ReverseEnumMap<V extends Enum<V> & EnumConverter<V>> {
private Map<String, V> map = new HashMap<String, V>();
public ReverseEnumMap(Class<V> valueType) {
for (V v : valueType.getEnumConstants()) {
map.put(v.convert(), v);
}
}
public V get(String pKey) {
return map.get(pKey);
}
}
Step 3
Go to you Enum class and implement it with EnumConverter<ContentType> and of course override interface methods. You also need to initialize a static ReverseEnumMap.
public enum ContentType implements EnumConverter<ContentType> {
VIDEO("Video"), GAME("Game"), TEST("Test"), IMAGE("Image");
private static ReverseEnumMap<ContentType> map = new ReverseEnumMap<ContentType>(ContentType.class);
private final String mName;
ContentType(String pName) {
this.mName = pName;
}
String value() {
return this.mName;
}
#Override
public String convert() {
return this.mName;
}
#Override
public ContentType convert(String pKey) {
return map.get(pKey);
}
}
Step 4
Now create a Communication class file and call it's new method to convert an Enum to String and String to Enum. I have just put main method for explanation purpose.
public class Communication<E extends Enum<E> & EnumConverter<E>> {
private final E enumSample;
public Communication(E enumSample) {
this.enumSample = enumSample;
}
public String resolveEnumToStringValue(E e) {
return e.convert();
}
public E resolveStringEnumConstant(String pName) {
return enumSample.convert(pName);
}
//Should not put main method here... just for explanation purpose.
public static void main(String... are) {
Communication<ContentType> comm = new Communication<ContentType>(ContentType.GAME);
comm.resolveEnumToStringValue(ContentType.GAME); //return Game
comm.resolveStringEnumConstant("Game"); //return GAME (Enum)
}
}
Click for for complete explanation
I'm not sure if it's the same in Java, but enum types in C are automatically mapped to integers as well so you can use either the type or integer to access it. Have you tried simply accessing it with integer yet?
Really great question :-) I used solution similar to Mr.Ferguson`s sometime ago. Our decompiled enum looks like this:
final class BonusType extends Enum
{
private BonusType(String s, int i, int id)
{
super(s, i);
this.id = id;
}
public static BonusType[] values()
{
BonusType abonustype[];
int i;
BonusType abonustype1[];
System.arraycopy(abonustype = ENUM$VALUES, 0, abonustype1 = new BonusType[i = abonustype.length], 0, i);
return abonustype1;
}
public static BonusType valueOf(String s)
{
return (BonusType)Enum.valueOf(BonusType, s);
}
public static final BonusType MONTHLY;
public static final BonusType YEARLY;
public static final BonusType ONE_OFF;
public final int id;
private static final BonusType ENUM$VALUES[];
static
{
MONTHLY = new BonusType("MONTHLY", 0, 1);
YEARLY = new BonusType("YEARLY", 1, 2);
ONE_OFF = new BonusType("ONE_OFF", 2, 3);
ENUM$VALUES = (new BonusType[] {
MONTHLY, YEARLY, ONE_OFF
});
}
}
Seeing this is apparent why ordinal() is unstable. It is the i in super(s, i);. I'm also pessimistic that you can think of a more elegant solution than these you already enumerated. After all enums are classes as any final classes.
For the sake of completeness, here is a generic approach to retrieve enum values by index from any enum type. My intention was to make the method look and feel like Enum.valueOf(Class, String). Fyi, i copied this method from here.
Index related issues (already discussed in depth here) still apply.
/**
* Returns the {#link Enum} instance for a given ordinal.
* This method is the index based alternative
* to {#link Enum#valueOf(Class, String)}, which
* requires the name of an instance.
*
* #param <E> the enum type
* #param type the enum class object
* #param ordinal the index of the enum instance
* #throws IndexOutOfBoundsException if ordinal < 0 || ordinal >= enums.length
* #return the enum instance with the given ordinal
*/
public static <E extends Enum<E>> E valueOf(Class<E> type, int ordinal) {
Preconditions.checkNotNull(type, "Type");
final E[] enums = type.getEnumConstants();
Preconditions.checkElementIndex(ordinal, enums.length, "ordinal");
return enums[ordinal];
}
Int -->String :
public enum Country {
US("US",0),
UK("UK",2),
DE("DE",1);
private static Map<Integer, String> domainToCountryMapping;
private String country;
private int domain;
private Country(String country,int domain){
this.country=country.toUpperCase();
this.domain=domain;
}
public String getCountry(){
return country;
}
public static String getCountry(String domain) {
if (domainToCountryMapping == null) {
initMapping();
}
if(domainToCountryMapping.get(domain)!=null){
return domainToCountryMapping.get(domain);
}else{
return "US";
}
}
private static void initMapping() {
domainToCountryMapping = new HashMap<Integer, String>();
for (Country s : values()) {
domainToCountryMapping.put(s.domain, s.country);
}
}
I needed something different because I wanted to use a generic approach. I'm reading the enum to and from byte arrays. This is where I come up with:
public interface EnumConverter {
public Number convert();
}
public class ByteArrayConverter {
#SuppressWarnings("unchecked")
public static Enum<?> convertToEnum(byte[] values, Class<?> fieldType, NumberSystem numberSystem) throws InvalidDataException {
if (values == null || values.length == 0) {
final String message = "The values parameter must contain the value";
throw new IllegalArgumentException(message);
}
if (!dtoFieldType.isEnum()) {
final String message = "dtoFieldType must be an Enum.";
throw new IllegalArgumentException(message);
}
if (!EnumConverter.class.isAssignableFrom(fieldType)) {
final String message = "fieldType must implement the EnumConverter interface.";
throw new IllegalArgumentException(message);
}
Enum<?> result = null;
Integer enumValue = (Integer) convertToType(values, Integer.class, numberSystem); // Our enum's use Integer or Byte for the value field.
for (Object enumConstant : fieldType.getEnumConstants()) {
Number ev = ((EnumConverter) enumConstant).convert();
if (enumValue.equals(ev)) {
result = (Enum<?>) enumConstant;
break;
}
}
if (result == null) {
throw new EnumConstantNotPresentException((Class<? extends Enum>) fieldType, enumValue.toString());
}
return result;
}
public static byte[] convertEnumToBytes(Enum<?> value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
if (!(value instanceof EnumConverter)) {
final String message = "dtoFieldType must implement the EnumConverter interface.";
throw new IllegalArgumentException(message);
}
Number enumValue = ((EnumConverter) value).convert();
byte[] result = convertToBytes(enumValue, requiredLength, numberSystem);
return result;
}
public static Object convertToType(byte[] values, Class<?> type, NumberSystem numberSystem) throws InvalidDataException {
// some logic to convert the byte array supplied by the values param to an Object.
}
public static byte[] convertToBytes(Object value, int requiredLength, NumberSystem numberSystem) throws InvalidDataException {
// some logic to convert the Object supplied by the'value' param to a byte array.
}
}
Example of enum's:
public enum EnumIntegerMock implements EnumConverter {
VALUE0(0), VALUE1(1), VALUE2(2);
private final int value;
private EnumIntegerMock(int value) {
this.value = value;
}
public Integer convert() {
return value;
}
}
public enum EnumByteMock implements EnumConverter {
VALUE0(0), VALUE1(1), VALUE2(2);
private final byte value;
private EnumByteMock(int value) {
this.value = (byte) value;
}
public Byte convert() {
return value;
}
}
Just because the accepted answer is not self contained:
Support code:
public interface EnumWithCode<E extends Enum<E> & EnumWithCode<E>> {
public Integer getCode();
E fromCode(Integer code);
}
public class EnumWithCodeMap<V extends Enum<V> & EnumWithCode<V>> {
private final HashMap<Integer, V> _map = new HashMap<Integer, V>();
public EnumWithCodeMap(Class<V> valueType) {
for( V v : valueType.getEnumConstants() )
_map.put(v.getCode(), v);
}
public V get(Integer num) {
return _map.get(num);
}
}
Example of use:
public enum State implements EnumWithCode<State> {
NOT_STARTED(0), STARTED(1), ENDED(2);
private static final EnumWithCodeMap<State> map = new EnumWithCodeMap<State>(
State.class);
private final int code;
private State(int code) {
this.code = code;
}
#Override
public Integer getCode() {
return code;
}
#Override
public State fromCode(Integer code) {
return map.get(code);
}
}
given:
public enum BonusType {
MONTHLY(0), YEARLY(1), ONE_OFF(2)
}
BonusType bonus = YEARLY;
System.out.println(bonus.Ordinal() + ":" + bonus)
Output:
1:YEARLY
If you have a class Car
public class Car {
private Color externalColor;
}
And the property Color is a class
#Data
public class Color {
private Integer id;
private String name;
}
And you want to convert Color to an Enum
public class CarDTO {
private ColorEnum externalColor;
}
Simply add a method in Color class to convert Color in ColorEnum
#Data
public class Color {
private Integer id;
private String name;
public ColorEnum getEnum(){
ColorEnum.getById(id);
}
}
and inside ColorEnum implements the method getById()
public enum ColorEnum {
...
public static ColorEnum getById(int id) {
for(ColorEnum e : values()) {
if(e.id==id)
return e;
}
}
}
Now you can use a classMap
private MapperFactory factory = new DefaultMapperFactory.Builder().build();
...
factory.classMap(Car.class, CarDTO.class)
.fieldAToB("externalColor.enum","externalColor")
.byDefault()
.register();
...
CarDTO dto = mapper.map(car, CarDTO.class);

Categories