Java static List - java

I want to pass a static list through an interface.
So that I can execute the following code.
updateSingleItem(new InformationListModule(getNameByUUID(uid), value));
I am looking for the cleanest way to create a static list where I can output the name based on an ID. I want to pass this list to different classes.
How can I create a static list with which I can execute the command "getNameByUUID(uid)".
Maybe someone can tell me what is the cleanest solution and give a small example.
would be glad.
Vielen Lieben dank.

I have now implemented it this way.
public abstract class BluetoothUUIDs {
/* UUID SERVICES */
public static final HashMap<String, String> BLE_SERVICE_UUID_NAME;
public static final HashMap <String, String> BLE_SERVICE_UUID_TYPE;
/* UUID ATTRIBUTES */
...
{
/* UUID SERVICES TO NAME */
BLE_SERVICE_UUID_NAME = new HashMap<>();
.....
BLE_SERVICE_UUID_TYPE.put("1800","org.bluetooth.service.generic_access");
...
I don't know if it's the best, but it's a way.

You could consider using an EnumMap.
import java.util.EnumMap;
public enum UUIDs {
UUID_1("1800", "org.bluetooth.service.generic_access"),
// additional UUID‘s..
private final String uuid;
private final String name;
UUIDs(String uuid, String name) {
this.uuid = uuid;
this.name = name;
}
public String getUuid() {
return uuid;
}
public String getName() {
return name;
}
private static final EnumMap<UUIDs, String> uuidToName = new EnumMap<>(UUIDs.class);
private static final EnumMap<UUIDs, String> uuidToType = new EnumMap<>(UUIDs.class);
static {
for (UUIDs uuid : UUIDs.values()) {
uuidToName.put(uuid, uuid.getName());
uuidToType.put(uuid, uuid.getUuid());
}
}
public static String getNameByUuid(String uuid) {
for (UUIDs u : UUIDs.values()) {
if (u.getUuid().equals(uuid)) {
return u.getName();
}
}
return null;
}
public static String getUuidByName(String name) {
for (UUIDs u : UUIDs.values()) {
if (u.getName().equals(name)) {
return u.getUuid();
}
}
return null;
}
}
You can access the EnumMap in other classes by calling the methods getNameByUuid and getUuidByName.
String name = UUIDs.getNameByUuid("1800");
String uuid = UUIDs.getUuidByName("org.bluetooth.service.generic_access");
This is a suggestion you could try/use.

Related

Duplicate code across enums .. is there an approach to centralize common code in these enums?

I have the following 3 enum's in my project, which are all very similar.
Since each enum has at least 2 common fields i.e key and code, is there any way that I can make the common:
constructors
getters
field declarations
shared to all of my enums? Without having to declare inside each one.
I know no extends clause allowed for enum.
But is there an elegant way to achieve reuse of the common parts of these enums?
public enum CarType {
SEAT("2000", "001"),
FIAT("3000", "002");
String key;
String code;
CarType(String key, String code) {
this.key = key;
this.code = code;
}
public String getKey() {
return key;
}
public String getCode() {
return code;
}
}
public enum TruckType {
MERCEDES("4000", "001"),
FORD("5000", "002");
String key;
String code;
TruckType(String key, String code) {
this.key = key;
this.code = code;
}
public String getKey() {
return key;
}
public String getCode() {
return code;
}
}
public enum VanType {
JEEP("6000", "001", "40"),
KIA("7000", "002", "50");
String key;
String code;
String tankSize;
VanType(String key, String code, String tankSize) {
this.key = key;
this.code = code;
this.tankSize = tankSize;
}
public String getKey() {
return key;
}
public String getCode() {
return code;
}
public String getTankSize() {
return tankSize;
}
}
Enum - is a special kind of class that is very restricted. And you may think of enum constants as if they are public static final fields (note: explicit modifiers are not allowed with enum constants).
That actually resembles the Singleton pattern.
All enum constants are eagerly initialized when an enum is being loaded into memory. And that is the simplest implementation of the singleton when an instance (in this case instances) is being initialed before any of its static methods of fields can be accessed.
My idea is to introduce an abstract class VehicleType that will contain two string fields key and code, constructor and getters.
And every enum will turn into a concrete class that extends the VehicleType class. Apart from constructors and static final fields in these classes, we'll need to declare only a single field inside the VanType and provide a getter for it.
The code for that will look like that.
public abstract class VehicleType {
protected String key;
protected String code;
public VehicleType(String key, String code) {
this.key = key;
this.code = code;
}
// getters + common behaviour
}
public class CarType extends VehicleType {
public static final CarType SEAT = new CarType("2000", "001");
public static final CarType FIAT = new CarType("3000", "002");
private CarType(String key, String code) {
super(key, code);
}
}
public class TruckType extends VehicleType {
public static final TruckType SEAT = new TruckType("4000", "001");
public static final TruckType FIAT = new TruckType("5000", "002");
private TruckType(String key, String code) {
super(key, code);
}
}
public class VanType extends VehicleType {
public static final VanType JEEP = new VanType("6000", "001", "40");
public static final VanType KIA = new VanType("7000", "002", "50");
private String tankSize;
private VanType(String key, String code, String tankSize) {
super(key, code);
this.tankSize = tankSize;
}
public String getTankSize() {
return tankSize;
}
}

Static Objects are not getting stored in HashMap.!

I am trying to create a Map with key as a String and Value as a static class. But when I am printing the data, it only stores the last key-value pair. Can someone help me with this.
import java.util.HashMap;
import java.util.Map;
public class MapImplementation {
public static class Asset {
public static String assetName;
public static String assetType;
private void setAssetName(String name) {
Asset.assetName = name;
}
private void setAssetType(String type) {
Asset.assetType = type;
}
private String getAssetName() {
return assetName;
}
private String getAssetType() {
return assetType;
}
}
public static void main(String[] args) {
Map<String, Asset> map = new HashMap<>();
Asset asset1 = new Asset();
asset1.setAssetName("Vodafone");
asset1.setAssetType("STOCK");
map.put("Vodafone", asset1);
Asset asset2 = new Asset();
asset2.setAssetName("Google");
asset2.setAssetType("STOCK");
map.put("Google", asset2);
Asset asset3 = new Asset();
asset3.setAssetName("IBM");
asset3.setAssetType("BOND");
map.put("IBM", asset3);
for (String str : map.keySet()) {
Asset ast = map.get(str);
System.out.println(ast.getAssetName()+" "+ast.getAssetType());
}
}
}
The output I am getting is:
IBM BOND
IBM BOND
IBM BOND
Change:
public static String assetName;
public static String assetType;
to:
public String assetName;
public String assetType;
static fields are class level, not instance level - they are shared across all instances. Even though you are calling setters of different objects, the exact same 2 fields are being updated in those methods.

Is there a way to share elements of overlapping maps?

This a little something I stumbled upon while programming and I wonder whether anyone could provide me with some insights here.
Imagine you have some enum-like classes, i.e. classes with loads of instances defined as constants of the class. As an example consider something like
public class ChildName {
private static final Map<String, ChildName> LUT = new TreeMap<>();
private final String name;
private ChildName(String name) {
this.name = name.toLowerCase();
LUT.put(name, this);
}
public static Collection<ChildName> getNames() {
return LUT.values();
}
public static ChildName fromValue(String name) {
return LUT.get(name);
}
public static final ChildName SARAH = new ChildName("Sarah");
public static final ChildName MEGAN = new ChildName("Megan");
public static final ChildName SANDY = new ChildName("Sandy");
public static final ChildName JOHN = new ChildName("John");
public static final ChildName BORIS = new ChildName("Boris");
// etc...
}
Now, one could argue that it might be necessary to split up between boy's names and girl's names (or consider names from different countries or whatever, you get the idea). The idea would be that you can still list all of the possible names, but also all the names for boys or all the names for girls. This could be done with something like
public class ChildName {
private static final Map<String, ChildName> LUT = new TreeMap<>();
private final String name;
protected ChildName(String name) {
this.name = name.toLowerCase();
LUT.put(name, this);
}
public static Collection<ChildName> getNames() {
return LUT.values();
}
public static ChildName fromValue(String name) {
return LUT.get(name);
}
// maybe here there are some gender-neutral names as constants left
public static final ChildName ALEX = new ChildName("Alex");
}
public class GirlsName {
private static final Map<String, ChildName> LUT = new TreeMap<>();
private GirlsName(String name) {
super(name);
LUT.put(name, this);
}
public static Collection<ChildName> getNames() {
return LUT.values();
}
public static final ChildName SARAH = new ChildName("Sarah");
public static final ChildName MEGAN = new ChildName("Megan");
public static final ChildName SANDY = new ChildName("Sandy");
// etc...
}
public class BoysName {
private static final Map<String, ChildName> LUT = new TreeMap<>();
private BoysName(String name) {
super(name);
LUT.put(name, this);
}
public static Collection<ChildName> getNames() {
return LUT.values();
}
public static final ChildName JOHN = new ChildName("John");
public static final ChildName BORIS = new ChildName("Boris");
// etc...
}
which could lead to huge Maps in each of the classes with massive overlaps.
There is probably not that much of a problem concerning efficiency or memory in this case, but despite that, it is still quite redundant and does not feel pretty.
It can be argued that the Map in the upper class could be omitted (assume the gender-neutral names are just duplicated in the subclasses or so) and the collection of all results could be retrieved from combining the collections of the subclasses. However, I would like to avoid this approach from a design point of view (imagine how messy that might get in case of a subclass for each country on this planet).
A more elegant solution (in my eyes) would be to keep a Map in every class, but in such a way that they share entries. Now I was wondering whether someone would now if this could be possible using a basic Map implementation. Other suggestions to solve this kind of problem are of course also welcome.
PS: I am aware that my proposal for an elegant solution is in fact not that much better, but I just can't come up with a better idea and I can't stop wondering how such kind of map could be implemented
Go one step further than enum-like, and make them enums:
interface ChildName {}
enum GirlsName implements ChildName {
Sarah, Megan, Sandy
}
enum BoysName implements ChildName {
John, Boris
}
Now look up map is not needed:
ChildName name = BoysName.valueOf("Boris");
I'll let you write the code to find either boy's or girl's name.
I would suggest using an actual enum, and instead of grouping them into distinct classes, storing attributes such as country and gender on the ChildName class, then filtering and grouping as necessary.
public enum Gender {
MALE, FEMALE
}
public enum Country {
USA, CA, UK
}
public enum ChildName {
SARAH(FEMALE, USA),
MEGAN(FEMALE, CA),
SANDY(FEMALE, UK),
JOHN(MALE, USA),
BORIS(MALE, UK);
private static final Map<String, ChildName> LUT;
static {
LUT = Array.stream(values())
.collect(Collectors.groupingBy(c -> c.name().toLowerCase()));
}
public static Collection<ChildName> getNames() {
return Arrays.asList(values());
}
public static ChildName fromValue(String name) {
return LUT.get(name.toLowerCase());
}
// some examples of filtering and grouping
// if necessary, they can be cached statically (like LUT)
public static List<String> getMaleNames() {
return Arrays.stream(values())
.filter(c -> c.getGender() == MALE)
.map(ChildName::name)
.collect(Collectors.toList());
}
public static Map<Gender, List<ChildName>> getGenderMapForCountry(Country country) {
return Arrays.stream(values())
.filter(c -> c.getCountry() == country)
.collect(Collectors.groupingBy(ChildName::getGender));
}
private final Gender gender;
private final Country country;
ChildName(Gender gender, Country country) {
this.gender = gender;
this.country = country;
}
public Gender getGender() {
return gender;
}
public Country getCountry() {
return country;
}
}

Esper: Grammatically defining a type with sub types?

I have to define the class below in ESPER so I'm able to reference the sub-types and internal arrays. I have to do it pragmatically. I don't care how:
UPDATE: The complete class:
public class IoTEntityEvent implements java.io.Serializable {
private IoTProperty[] Properties;
private String About;
IoTEntityEvent (){
this.About = null;
this.Properties = null;
}
public String getAbout() {
return About;
}
public void setAbout( String value){
this.About = value;
}
public void setProperties(int index, IoTProperty value) {
Properties[index] = value;
}
public IoTProperty getProperties(int index) {
return Properties[index];
}
public void setProperties( IoTProperty[] value) {
Properties = value;
}
public IoTProperty[] getProperties() {
return Properties;
}
}
This is the sub-class:
public class IoTProperty implements java.io.Serializable {
private Map<String,String>[] IoTStateObservation =null;
private String About = null;
IoTProperty (){
this.About = null;
this.IoTStateObservation = null;
}
public String getAbout() {
return About;
}
public void setAbout(String value) {
About = value;
}
public Map<String,String>[] getIoTStateObservation() {
return IoTStateObservation;
}
public void setIoTStateObservation( Map<String,String>[] value) {
IoTStateObservation = value;
}
public Map<String,String> getIoTStateObservation(int index) {
return IoTStateObservation[index];
}
public void setIoTStateObservation(int index, Map<String,String> value) {
IoTStateObservation[0] = value;
}
}
I tried like this :
eventNames[0] = "About";
eventType[0] = String.class;
eventNames[1] = "Properties";
eventType[1] = IoTProperty[].class;
epService.getEPAdministrator().getConfiguration().addEventType("type", eventNames, eventType);
This works but I can't access the sub-types. I also tried to define the sub type in similar manner. Can someone can explain how I suppose to do it?
What do you mean with "This works but I can't access the sub-types."
Tried like "select Properties[0].whatever" from type?
According to the Esper documentation:
Plain-old Java object events are object instances that expose event properties through JavaBeans-style getter methods. Events classes or interfaces do not have to be fully compliant to the JavaBean specification; however for the Esper engine to obtain event properties, the required JavaBean getter methods must be present or an accessor-style and accessor-methods may be defined via configuration.
In short, you need to create the JavaBean getters and setters in order to access your private members.
Thank you for the help. I found out how and is as following:
epService.getEPAdministrator().getConfiguration().addEventType("type",IoTEntityEvent.class);
Then the event should be send like this without any casting:
IoTValue[] va= {new IoTValue("0.62","2014-06-09T18:08:40.968Z","2014-06-09T18:08:40.968Z")};
IoTProperty[] pr = {new IoTProperty(va,"property")};
IoTEntityEvent event = new IoTEntityEvent(pr,"Entity");
epService.getEPRuntime().sendEvent(event);

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