Exchanging data between 2 methods in 2 different classes - java

Im quite new to Java and this might be a basic doubt. But please help.
I have a class as below:
public class EnterLeaveHandler implements IOtfHandler {
public void handle(java.lang.Object ... args) {
long time = (Long) args[0];
int func = (Integer) args[1];
int cpuid = (Integer) args[2];
int source = (Integer) args[3];
}
I have another class:
public class DefFunctionHandler implements IOtfHandler {
public void handle(Object... args) {
int stream = (Integer) args[0];
int func = (Integer) args[1];
String name = (String) args[2];
int funcgroup = (Integer) args[3];
int source = (Integer) args[4];
}
}
So like you can see..there are 2 different classes, which have the same method, but receive different data. I need to get an input from the user for the "String name" in DefFunctionHandler class, and I identify the given name with the name in the file that I have...then correlate it with other data in the method like funcgroup and func. The same func is there in the other class too. So I need to make a comparison between them to get the data in the other class like time, etc.
So the data in the methods can be compared to the data structure in C...how do I implement such a structure in Java? I read that structs are similar to classes in Java. But in my case, I have the data in methods and not classes. Please tell me how to solve this problem.

To Answer Your Original Question
Long story short, you can't access method variables externally. What you want to do is make those variables fields within the class. Putting them outside the method means they stick around after the method is done, and it means you can access them from outside.
public class EnterLeaveHandler implements IOtfHandler {
private long time;
private int func;
private int cpuid;
private int source;
// Please don't use varargs like this; read the whole answer!!
public void handle(Object ... args) {
time = (Long) args[0];
func = (Integer) args[1];
cpuid = (Integer) args[2];
source = (Integer) args[3];
}
}
Then you access them by creating getters and setters:
public long getTime() {
return time;
}
public void setTime(long t) {
time = t;
}
// etc...
HOWEVER, Some Suggestions...
Your code is... strange, to say the least. It's also very non-Java-like. As much as possible, you should try to avoid having multiple overriding methods that need different data. Also, you normally want to initialize your fields in the constructor, not in some other method.
It's not clear how much of the code you have access to, but if you're able to rewrite the interface, I would definitely do so. Object varargs in an interface is just weird. The reason for using an interface is so that you can call an interface method with identical parameters and, regardless of the object type underneath, something useful will happen. It defeats the point of the interface to have two implementations of the same method require totally different arguments. The following code demonstrates why this is:
IOtfHandler h1 = new EnterLeaveHandler();
IOtfHandler h2 = new DefFunctionHandler();
h1.handle(0, 0, 0, 0);
h2.handle(0, 0, 0, 0); // Crashes with ClassCastException!! :(
// And would also crash two lines later with ArrayIndexOutOfBoundsException
Much better to just make them different methods entirely.You know what variables you're expecting, so you should take advantage of that fact. Your method signatures would be far better off looking something like this:
public class EnterLeaveHandler implements IOtfHandler {
public void handle(long time, int func, int cpuid, int source) {
// Do things with your shiny new variables
}
public class DefFunctionHandler implements IOtfHandler {
public void handle(int stream, int func, String name, int funcgroup, int source) {
// Do things with your shiny new variables
}
}
As others have suggested, if the "real" method signatures are not identical, you shouldn't be using an interface. Better to use an abstract base class instead, to hold what little data is common between them:
abstract class IOtfHandler {
private int source;
private int func;
public void setSource(int source) {
this.source = source;
}
// etc
}
class EnterLeaverHandler extends IOtfHandler {
private long time;
// etc
}
class DefFunctionHandler extends IOtfHandler {
private String name;
// etc
}
Of course, if you set all the variables in the constructors, you may be able to add an abstract handle() method to the base class, since then that method should have the same signature, and take no arguments at all!
Final Result
So if we pull together all the changes I've talked about-- moving the method variables into fields, using getters and setters, using useful method signatures, using constructors, and using a base class instead of a misleading interface, we end up with something like this:
abstract class IOtfHandler {
private int source;
private int func;
public void setSource(int source) {
this.source = source;
}
public int getSource() {
return source;
}
public void setFunc(int func) {
this.func = func;
}
public int getFunc() {
return func;
}
// abstract handle method
abstract public void handle();
}
class EnterLeaverHandler extends IOtfHandler {
private long time;
private int cpuid;
// getters and setters
public void setTime(long time) {
this.time = time;
}
public long getTime() {
return time;
}
public void setCpuId(int cpuid) {
this.cpuid = cpuid;
}
public int getCpuId() {
return cpuid;
}
// constructor
public EnterLeaverHandler(long time, int cpuid, int source, int func) {
setTime(time);
setCpuId(cpuid);
setSource(source);
setFunc(func);
}
// handle method
public void handle() {
System.out.println("EnterLeaverHandler.handle()");
// Do whatever class-specific handling you might want to do in here.
}
}
class DefFunctionHandler extends IOtfHandler {
private String name;
private int funcGroup;
private int stream;
// getters and setters
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setFuncGroup(int funcGroup) {
this.funcGroup = funcGroup;
}
public int getFuncGroup() {
return funcGroup;
}
public void setStream(int stream) {
this.stream = stream;
}
public int getStream() {
return stream;
}
// constructor
public DefFunctionHandler(String name, int funcGroup, int stream, int source, int func) {
setName(name);
setFuncGroup(funcGroup);
setStream(stream);
setSource(source);
setFunc(func);
}
// handle method
public void handle() {
System.out.println("DefFunctionHandler.handle()");
// Do whatever class-specific handling you might want to do in here.
}
}
public class Main {
public static void main(String[] args) {
IOtfHandler h1 = new DefFunctionHandler("name", 0, 0, 0, 0);
IOtfHandler h2 = new EnterLeaverHandler(0, 0, 0, 0);
h1.handle();
h2.handle();
}
}

In order to make the variables class variables, all you have to do is move their declaration outside of the method. In other words, your code for the EnterLeaveHandler might look like this:
public class EnterLeaveHandler implements IOtfHandler {
long time;
int func;
int cpuid;
int source;
public void handle(java.lang.Object ... args) {
time = (Long) args[0];
func = (Integer) args[1];
cpuid = (Integer) args[2];
source = (Integer) args[3];
...
}
}

Create an abstract super class for your classes. Extend this with your classes and init the parameters in the handle call.
public abstract class AbstarctFunctionHandler implements IOtfHandler {
long time;
int func;
int cpuid;
int source
//add getters and setters, if you fancy
public boolean equals(AbstarctFunctionHandler obj){
//compare variables
return true;
}
}

You need to restructure your objects to have proper constuctors and setters/getters
This gives the benefit of protecting all your private variables and forcing other classes to adhere to your classe's "contract" by only allowing them to access it's inner variables via those setters/getters and constructor. Now you just instantiate the object, then use ti's methods to manipulate it.
Here is an example from your first example class:
public class EnterLeaveHandler implements IOtfHandler {
private long time;
private int func, cpuid, source;
public EnterLeavehandler(long time, int func, int cpuid, int source) {
this.time = time;
this.func = func;
this.cpuid = cpuid;
this.source = souce;
}
public long getTime() {
return this.time;
}
public void setTime(long time) {
this.time = time;
}
public int getFunc() {
return this.func;
}
public void setFunc(int func) {
this.func = func;
}
public int getCPUID() {
return this.cpuid;
}
public void setCPUID(int cpuid) {
this.cpuid = cpuid;
}
public int getSource() {
return this.source;
}
public void setSource(int source) {
this.source = source;
}
public void handle(long t, int f, int c, int s) {
this.setTime(t);
this.setFunc(f);
this.setCPUID(c);
this.setSource(s);
}
}

The best solution I could think of
1. is create a getter and setter
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
http://docs.oracle.com/javaee/6/tutorial/doc/gjbbp.html
2.create a wrapper method to do the comparsion prior to calling the individual method.
Hope this helps you.

Related

How can I print an arraylist that is in one class, by a grouping from another class?

I'm trying to print an arraylist that is in one class, based on one of the parameters from another class. Is this possible?
import java.util.ArrayList;
public class TVShow {
private String title;
private String summary;
private String releaseDate;
private ArrayList<Episode> episodeList;
public TVShow(String title, String summary, String releaseDate) {
this.title = title;
this.summary = summary;
this.releaseDate = releaseDate;
this.episodeList = new ArrayList<>();
}
public void addEpisode(Episode episode) {
episodeList.add(episode);
}
public printEpisodesInSeason(int seasonNr) {
// How can I make this method access the other class and
// print the episodeList by season number?
for (Episode episode : episodeList) {
return System.out.println(episode.);
}
}
}
public class Episode {
private int episodeNr;
private int seasonNr;
private String eTitle;
private int runTime;
public Episode(int episodeNr, int seasonNr, String eTitle, int runTime) {
this.episodeNr = episodeNr;
this.seasonNr = seasonNr;
this.eTitle = eTitle;
this.runTime = runTime;
}
}
EDIT: I think I misinterpreted the question. You want to only print the episodes from a specific season. This can be done by applying the filter function on the episodeList as follows:
for (Episode episode : episodeList.stream().filter(episode -> episode.getSeasonNr() == seasonNr).collect(Collectors.toList()))
{ ... }
This is ofcourse assuming you apply the getter setter pattern as described below before I edited the answer.
The filter function takes an anonymous function and applies it to all members of a collection. This way, only the episodes which have a season number that is supplied by the user are returned. Then, the foreach loop iterates over the resulting collection.
You could either make the members of Episode public by defining:
public class Episode {
public int episodeNr;
public int seasonNr;
public String eTitle;
public int runTime;
public Episode(int episodeNr, int seasonNr, String eTitle, int runTime) {
this.episodeNr = episodeNr;
this.seasonNr = seasonNr;
this.eTitle = eTitle;
this.runTime = runTime;
}
}
But this is seen as bad practice. The better way to do it is by defining methods in your Episode class to return the value of the class' fields like for example:
public class Episode {
public int episodeNr;
public int seasonNr;
public String eTitle;
public int runTime;
public Episode(int episodeNr, int seasonNr, String eTitle, int runTime) {
this.episodeNr = episodeNr;
this.seasonNr = seasonNr;
this.eTitle = eTitle;
this.runTime = runTime;
}
public String getTitle() {
return this.eTitle;
}
}
This practice is called getters and setters and it positively impacts the encapsulation of the code. You could then obtain the value of the Episode's members by calling, for example episode.getTitle().

Is it correct to have static factory method to get a new instance with one field updated?

I think the title is self-descriptive but I will give an example to elaborate on my question. I have a DTO class with few fields (a CarDataTransferObj class in my example). In another class (let's call it class A) I need to create a new instance of that object few times, but with only one field updated (length field in my example). Given DTO must be immutable in class A. As there is "many" fields in the class CarDataTransferObj, I thought about following approach (to avoid repeating code in class A):
#Builder
public class CarDataTransferObj {
private Integer id;
private String color;
private String manufacturer;
private String model;
private String uniqueIdNr;
private Integer nrOfDoors;
private EngineType engineType;
private Integer length;
private Integer safetyLevel;
public static CarDataTransferObj newInstanceWithUpdatedLength(final CarDataTransferObj car, final Integer newLength) {
return CarDataTransferObj.builder()
.id(car.getId())
.color(car.getColor())
.manufacturer(car.getManufacturer())
.model(car.getModel())
.uniqueIdNr(car.getUniqueIdNr())
.nrOfDoors(car.getNrOfDoors())
.engineType(car.getEngineType())
.length(newLength)
.safetyLevel(car.getSafetyLevel())
.build();
}
}
For me it smells like a little anti-pattern usage of static factory methods. I am not sure whether it's acceptable or not, hence the question.
Is using static factory method in the presented way an anti-pattern, and should be avoided ?
In my searching, I didn't come across anyone calling this1 an anti-pattern.
However, it is clear that if you try to do this using a classic builder that is not specifically implemented to support this mode of operation .... it won't work. For instance, the example CarBuilderImpl in the Wikipedia article on the Builder design pattern puts the state into an eagerly created Car instance. The build() method simply returns that object. If you tried to reuse that builder in the way that you propose, you would end up modifying a Car that has already been built.
There is another problem you would need to worry about. In we modified the Wikipedia CarBuilder example to add actual wheels (rather than a number of wheels) to the Car being built, we have to worry about creating cars that share the same wheels.
You could address these things in a builder implementation, but it is unclear whether the benefits out-weigh the costs.
If you then transfer this thinking to doing this using a factory method, you come to a slightly different conclusion.
If you are doing this as a "one-off", that's probably OK. You have a specific need, the code is clunky ... but so is the problem.
If you needed to do this for lots of different parameters, or combinations of parameters, this is not going to scale.
If the objects that are created are mutable, then this approach is could be problematic in a multi-threaded environment depending on how you control access to the objects you are using as templates.
1 - There are no clear measurable criteria for whether something is an anti-pattern or not. It is a matter of opinion. Admittedly, for many anti-patterns, there will be wide-scale agreement on that opinion.
It seems a little inefficient to construct an entirely new instance via a builder every time you want to make a new copy with a small modification. More significantly, it sounds like the places where you need the class to be immutable are isolated to places like class A. Why not try something like this:
public interface ICarDataTransferObject {
public Integer GetId();
public String GetColor();
public String GetManufacturer();
public String GetModel();
public String GetUUID();
public Integer GetDoorCount();
public EngineType GetEngineType();
public Integer GetLength();
public Integer GetSafteyLevel();
}
public class CarDataTransferObject Implements ICarDataTransferObject {
private Integer _id;
private String _color;
private String _manufacturer;
private String _model;
private String _uniqueIdNr;
private Integer _nrOfDoors;
private EngineType _engineType;
private Integer _length;
private Integer _safetyLevel;
public Integer GetId() { return _id; }
public void SetId(Integer id) { _id = id; }
public String GetColor() { return _color; }
public void SetColor(String color) { _color = color; }
public String GetManufacturer() { return _manufacturer; }
public void SetManufacturer(String manufacturer) { _manufacturer = manufacturer; }
public String GetModel() { return _model; }
public void SetModel(String model) { _model = model; }
public String GetUUID() { return _uniqueIdNr; }
public void SetUUID(String uuid) { _uniqueIdNr = uuid; }
public Integer GetDoorCount() { return _nrOfDoors; }
public void SetDoorCount(Integer count) { _nrOfDoors = count; }
public EngineType GetEngineType() { return _engineType; }
public void SetEngineType(EngineType et) { _engineType = et; }
public Integer GetLength() { return _length; }
public void SetLength(Integer length) { _length = length; }
public Integer GetSafteyLevel() { return _safetyLevel; }
public void SetSafteyLevel(Integer level) { _safteyLevel = level; }
public CarDataTransferObject() {}
public CarDataTransferObject(ICarDataTransferObject other) { ... }
public ReadOnlyCarDataTransferObject AsReadOnly() {
return ReadOnlyCarDataTransferObject (this);
}
}
}
public class ReadOnlyCarDataTransferObject Implements ICarDataTransferObject {
private ICarDataTransferObject _dto = null;
public Integer GetId() { return _dto.GetId(); }
public String GetColor() { return _dto.GetColor(); }
public String GetManufacturer() { return _dto.GetManufacturer(); }
public String GetModel() { return _dto.GetModel(); }
public String GetUUID() { return _dto.GetUUID(); }
public Integer GetDoorCount() { return _dto.GetDoorCount(); }
public EngineType GetEngineType() { return _dto.GetEngineType(); }
public Integer GetLength() { return _dto.GetLength(); }
public Integer GetSafteyLevel() { return _dto.GetSafteyLevel; }
public ReadOnlyCarDataTransferObject (ICarDataTransferObject other) {
_dto = other;
}
}
Now when you want class A to have a copy no one can modify, just use the copy constructor and only expose a ReadOnly version of that copy.
public class A {
ICarDataTransferObject _dto;
ReadOnlyCarDataTransferObject _readOnlyDTO;
public ICarDataTransferObject GetDTO() { return _readOnlyDTO; }
public A(ICarDataTransferObject dto) {
_dto = new CarDataTransferObject(dto);
_readOnlyDTO = new ReadOnlyCarDataTransferObject(_dto);
}
}
You commonly see this approach in .NET applications.
While it is debatable whether your static method is an anti-pattern or not, it surely won't scale for combinations of different attributes. Nonetheless, even if it's not an anti-pattern, I think there is a better way to accomplish what you need.
There's a variant of the traditional builder pattern that, instead of creating a new empty builder, accepts an already built object and creates an already initialized builder. Once you create the builder this way, you simply change the length attribute in the builder. Finally, build the object. In plain code (no Lombok, sorry) it could be like this:
public class CarDataTransferObj {
private Integer id;
private String color;
// other attributes omitted for brevity
private Integer length;
// Private constructor for builder
private CarDataTransferObj(Builder builder) {
this.id = builder.id;
this.color = builder.color;
this.length = builder.length;
}
// Traditional factory method to create and return builder
public static Builder builder() {
return new Builder();
}
// Factory method to create and return builder initialized from an instance
public static Builder builder(CarDataTransferObj car) {
Builder builder = builder();
builder.id = car.id;
builder.color = car.color;
builder.length = car.length;
return builder;
}
// getters
public static class Builder {
private Integer id;
private String color;
private Integer length;
private Builder() { }
public Builder withId(Integer id) { this.id = id; return this; }
public Builder withColor(String color) { this.color = color; return this; }
public Builder withLength(Integer length) { this.length = length; return this; }
public CarDataTransferObj build() {
return new CarDataTransferObj(this);
}
}
}
Now with all this infrastructure in place, you can do what you want as easy as:
CarDataTransferObj originalCar = ... // get the original car from somewhere
CarDataTransferObj newCar = CarDataTransferObj.builder(originalCar)
.withLength(newLength)
.build();
This approach has the advantage that it scales well (it can be used to change any combination of parameters). Maybe all this builder's code seems boilerplate, but I use an IntelliJ plugin to create the builder with two keystrokes (including the variant factory method that accepts a built instance to create an initialized builder).
I'm still new to java but..
I guess making a copy method which takes the CarDataTransferObj object variables and sets their values to another CarDataTransferObj object variables and changing the the length using it's setter method would be better idea
Example:
public class CarDataTransferObj {
private Integer id;
private String color;
private String manufacturer;
private String model;
private String uniqueIdNr;
private Integer nrOfDoors;
private EngineType engineType;
private Integer length;
private Integer safetyLevel;
public void Copy(CarDataTransferObj copy) { //Could add another parameter here to be the new length
copy.setId(id);
copy.set(color);
copy.setManufacturer(manufacturer);
copy.setModel(model);
copy.setUniqueIdNr(uniqueIdNr));
copy.setNrOfDoors(nrOfDoors));
copy.setEngineType(engineType));
copy.setLength(length);
copy.setSafetyLevel(safetyLevel));
}
}
public class SomeOtherClass {
CarDataTransferObj car1 = new CarDataTransferObj(); //Using this way made you able to use the constructor for a more useful thing
//You set the variables you want for car1 here
CarDataTransferObj car2 = new CarDataTransferObj();
car1.Copy(car2)
car2.setLength(newLength) //Set the new length here
}

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);

accessing elements of a linked list that is made up of a private custom class

in a project i am trying to get two or more agents to communicate between each other to collect things in the environment. to do this i am using a mailbox containing messages that they would respond to depending on the messages sent ebtween each other. below is where i create the linked list
mailbox = new LinkedList[numberOfAgents()];
for ( int i=0; i< numberOfAgents(); i++ ){
mailbox[i] = new LinkedList<Message>();
mailbox[i].add(new Message(i, knownBloodBanks, knownDonors));
}
and then the private message and intention classes
private class Message
{
// instance variables
private int senderId;
private BoardComponentList donors;
private BoardComponentList bloodBanks;
private BoardComponent requestAssistanceAt;
private Intention iIntendToAssistAt;
public Message( int senderId, BoardComponentList d, BoardComponentList b )
{
this.senderId = senderId;
donors = d;
bloodBanks = b;
} // end constructor
public void setIntentions( Intention intention )
{
iIntendToAssistAt = intention;
}
public void setRequest( BoardComponent bC )
{
requestAssistanceAt = bC;
}
public BoardComponentList getDonors()
{
return donors;
}
public BoardComponentList getBloodBanks()
{
return bloodBanks;
}
public Intention getIntentions()
{
return iIntendToAssistAt;
}
public BoardComponent getRequest()
{
return requestAssistanceAt;
}
public int getSenderId()
{
return senderId;
}
} // end Message class
private class Intention
{
// instance variables
private BoardComponent target;
private double distanceTo;
public Intention( BoardComponent bC, double distance )
{
target = bC;
distanceTo = distance;
} // end constructor
public BoardComponent getTarget()
{
return target;
}
public double getDistancetoTarget()
{
return distanceTo;
}
}
i cant for the life of me figure out how to access the methods inside the private class so that i can set goals and see the messages between agents. any help or pointers in the right direction would be greatly appreciated, i hope i've included enough info if not please let me know anything else needed
i didnt explain myself clearly as i so often find problems with but yes both the private classes and the first code snippet are found inside a public class
There can be only one public class per file.
The name of the file name(program name) should match with the name
of the pubic class.
There can be multiple private classes inside your public class as
inner classes.
Sample code below ( modified your classes a bit because they we giving compilation error):
package com.pkg1;
import java.util.LinkedList;
public class Sample{
public Sample(){
LinkedList[] mailbox = new LinkedList[10];
for ( int i=0; i< 10; i++ ){
mailbox[i] = new LinkedList<Message>();
mailbox[i].add(new Message(i));
}
}
private class Message
{
// instance variables
private int senderId;
private Intention iIntendToAssistAt;
public Message( int senderId )
{
this.senderId = senderId;
} // end constructor
public void setIntentions( Intention intention )
{
iIntendToAssistAt = intention;
}
public Intention getIntentions()
{
return iIntendToAssistAt;
}
public int getSenderId()
{
return senderId;
}
} // end Message class
private class Intention
{
// instance variables
private double distanceTo;
public Intention( double distance )
{
distanceTo = distance;
} // end constructor
public double getDistancetoTarget()
{
return distanceTo;
}
}
}

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