Convert enum to class and vice versa - java

Currently, we have an business entity can be represented both as an enum or as a class.
The class implementation is easier and make business logic more clear. But there is probability of 50% that the requirements will change and an enum representation will make our life easier.
Concrete example
An entity has title and color. Color is editable, so there 2 ways
entity is an enum - there is another class with mapping from entity to its color.
entity is a class - just one more fiels for color, no problems.
Future change requirement - there should be rules associated with each entity
entity is an enum - the rules are hard coded in the code
entity is a class - there are needed few more classes for mapping and also an UI that will allow user to specify them.
In case the set of rules is static, the second option is an overkill.
So, in case we will need to transform the class to enum, are there any recommendations about this process ?
EDIT
The set of entities is limited and unlikely to be changed by user.
Thank you in advance.

If it has anything editable, you will need an entity class at some point anyway so go for the entity class first.
In case you have later a requirement for implementing a fixed set of rules, implement them as an enum with the hard coded rules, and add a field on your entity class that maps to that enum.
You can map enum on entity fields like this:
enum MyRule {
RULE1, RULE2;
// implement hard-coded rule
}
#Entity
class Myentity {
#Enumerated(/* optionally specify EnumType, default is ordinal */)
#Column
MyRule rule;
}

In case you want some functionality from enums and some from classes, then you could use mix of these:
public class ColoredTitle
{
private String color;
private Title title;
public ColoredTitle(String color, Title title)
{
this.color = color;
this.title = title;
}
public String getColor()
{
return color;
}
public void setColor(String color)
{
this.color = color;
}
public String getHeading()
{
return title.heading;
}
enum Title
{
FRONT_PAGE("Front Page"),
FOOTER_TITLE("Footer Title");
private String heading;
Title(String title)
{
this.heading = title;
}
}
}

Assuming that Entity means JPA entities.
You can use enum to return out to out side world and inside entity you can have property that represents it.
#Entity
class Entity {
#Column
Integer ruleIndex = 0;//Illustration purpose only
public Color getColor() {
// ruturn color based on rule that will be applied by ruleindex
}
}
enum Color {
BLUE(0), BLACK(1), WHITE(2);
private int ruleIndex = 0;
private Color(int ruleIndex) {
this.ruleIndex = ruleIndex;
}
}
Update
It is not advisable to use enums as entities. Instead you can use Single inheritance strategy
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="DISC", discriminatorType=STRING,length=20)
public class Color
{......}
#Entity
#DiscriminatorValue("Blue")
public class Blue extends Color
{......}
#Entity
#DiscriminatorValue("Green")
public class Green extends Color
{......}
This will allow you to store all the data in the same table and will allow you to also identify data based on objects.

Enums can have methods just like ordinary classes.
public enum Tree {
FIR("Fir Tree"),
BIRCH("Birch Tree");
private String desc;
public Tree(String desc) { this.desc = desc; }
public String getDesc() { return desc; }
public String getRandom() { return "abc"; }
}

Related

How to serialize and deserialize multi argument enum in Java using JPA 2.1 or lower (Postgres)

public enum CameraType {
CAMERA(false, false, "External lens ", ""),
CameraType{
boolean collector,
boolean hidden,
String description
) {
this.collector = collector;
this.granular = hidden;
this.description = description;
} // end ctor
public void setHide(boolean hidden) {
this.hide = hidden;
}
} // end enum
I have few Instance of CameraType.
I have a setter for "hidden" property which on certain condition is set to true or false.
Now I serialize CameraType with few other fields inside SecurityEntity.
```
#Entity
#Table
public class Security {
Few more fields...
#Enumerated(EnumType.STRING)
#Column(nullable = false)
private CameraType cameraType
And other fields...
}
```
When I deserialize the value of "hidden" field is always false. If I understand correctly, during deserialization ctor is called and default is assigned.
Is there a way I can retain the value of "hidden" field(true or false) after deserialization per instance of CameraType.
I am using Postgres DB 10.
enter code here
Please Please help. I am out of clues.
By definition, enums are immutable elements of a fixed set. Because of this, to represent an enum value you just need its name. That's exactly what JPA does during serialization/deserialization.
You are trying to violate the rules. While Java allows you to treat enums almost as plain objects, JPA treats them according to what they are supposed to be. That's why your code is not working.
You can either:
make CameraType into a class and serialize it as such, or
split CameraType into two parts, for example enum CameraType (immutable) and class CameraConfig (with all the mutable fields)
The former answer is correct : enums must be immutable and dividing parts into immutable and mutable data is a good choice.
One addition here: using the enum values for database storage is often not a good choice, because when another developer decides to refactor the enum names and you are after this reading old entries from database, you got a crashing application...
So I would suggest to use javax.persistence.AttributeConverter to deserialize/serialize an enum in a specific and rename save way.
Here a very simple example with an enum called MyDefinition:
enum MyDefinition{
ONE("def_one"),
TWO"def_two"),
THREE("def_three"),
;
private String id;
private MyDefinition(String id){
this.id=id;
}
public String getId(){
return id;
}
public static MyDefinition fromId(String id) {
for (MyDefinition definition : MyDefinition.values()) {
if (definition.id.equals(id)) {
return definition;
}
}
return null;
}
}
Here the converter:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
#Converter(autoApply = true)
public class MyDefinitionAttributeConverter implements AttributeConverter<MyDefinition, String> {
#Override
public String convertToDatabaseColumn(MyDefinition attribute) {
if (attribute == null){
return null;}
}
return attribute.getId();
}
#Override
public MyDefinition convertToEntityAttribute(String dbData) {
return MyDefinition.fromId(dbData);
}
So we can use the ids for database. A renaming of the enum names will no longer lead to a crashing application when reading old data.

Java - Possible use of Strategy Design Pattern?

public class ClassA_V01 {
private String name;
private int age;
// getter and setter
}
public class ClassA_V02 {
private String name;
private int age;
private int gender;
// getter and setter
}
public static void main(String[] args) {
SomeClass classA = new ClassA_V01();
classA.setName("myName);
classA.setAge(99);
performLogic(classA);
// OR
SomeClass classA = new ClassA_V02();
classA.setName("myName);
classA.setAge(99);
classA.setAge(1);
performLogic(classA);
}
public void performLogic(SomeClass classA) {
// do something
}
For strategy pattern to work, both classes must implement the same methods defined in the interface. But what if the classes need to have different fields and methods?
In my example, ClassA_V01 and ClassA_V02 are the same class except that one has more attribute "gender"
How does one implement the above such that classA can be equals to either ClassA_V01() or ClassA_V02?
"...For strategy pattern to work, both classes must implement the same methods defined in the interface. But what if the classes need to have different fields and methods?..." really this is not a criteria for strategy pattern.
Strategy pattern's intent is to identify and make family of algorithms interchangeable. If you read the pattern's documentation carefully, Strategy can be used when many related classes differ only in their behavior.
Appropriate decomposition is the key for better (extendable) design. A typical (but primitive) solution to Employee assignment, sub-classing tempEmp and permanentEmp types will put us in trouble and will not allow temp employee to become permanent in its life time (which has no meaning in real terms). This happens because we miss an important point- each employees employeeness is not different, they are all same type of employees with different pay policies. (same logic can be extended for Leave policy and so on)
This becomes simple if all types of employees have Salary computation based on same components (same state). But your question is what if TempEmployee gets only basicPay whereas PermanentEmployee gets basicPay as well as travelAllowance (additional attribute which is not present for TempEmp). This can be modeled by a combination of simple inheritance hierarchy along with strategy taking care of computation algorithm dependent upon Employee's (aka. Context) attribute (age)
public class Employee {
//name and id
private PayPackage payPackage;
private int age;
PayPackage strategy;
public double computeSalary() {
return payPackage.computePay(age);
}
//get/setPayPackage(...)
}
public abstract class PayPackage {
private double basicPay;
abstract public double computePay(int age);
protected double getBasicPay(){
return basicPay;
}
}
public class TempPayPackage extends PayPackage{
#Override
public double computePay(int age) {
double veteranAllowance = 0;
if (age > 40) {
veteranAllowance = 2000.00;
}
return getBasicPay() + veteranAllowance;
}
}
public class PermanentPayPackage extends PayPackage{
private double travelAllowance;
#Override
public double computePay(int age) {
double veteranAllowance = 0;
if (age > 40) {
veteranAllowance = 5000.00;
}
return getBasicPay() + travelAllowance + veteranAllowance;
}
}
Important thing to remember is Design patterns never work alone or as an alternative, they work hand in hand with Object oriented code and other patterns.

Assigning enum to Items

Some background on the project: I am attempting to craft a space/sci-fi combat sim game with tabletop rpg style dice mechanics cranked up to 11 on the complexity scale, but still being transparent about the die rolls going on under the hood. I'm currently using the Star Wars Saga Edition combat rules as a basis.
Currently I'm trying to figure out a way to assign traits to vehicle.(possibly stored as a class for each vehicle) Each trait is an enum so that it can store multiple pieces of information. Here is the code I have for size categories:
public enum VehicleSize {
LARGE(1,"Speeder bike",5),HUGE(2,"Small Fighter",10),GARGANTUAN(5,"Tank, Medium Fighter",20),COLOSSAL(10,"Imperial Walker, Light Freighter",50),
COLLOSSALfrigate(10,"Corvette, Frigate",100),COLLOSSALcruiser(10,"Imperial-class Star Destroyer, Cruiser",200),
COLLOSSALstation(10,"The Death Star, Space Station",500);
private final int refMod;
private final int threshMod;
private final String desc;
VehicleSize(int reflexModifier,String example,int thresholdModifier)
{
refMod = reflexModifier;
desc = example;
threshMod = thresholdModifier;
}
public int getRefMod() {
return refMod;
}
public String getDesc() {
return desc;
}
public int getThreshMod() {
return threshMod;
}
}
My question is such: How do create vehicle profiles in such a way that I can assign this and similar enums as traits?
For practically all purposes, a field whose type is an enum class is no different than a field of any other object type, like Integer or String.
Create a private field, add a getter and setter, or if the field is final (likely in your case, because a vehicle instance can't change its type), add it as a constructor parameter and remo e the setter.
public class Vehicle {
private final VehicleSize vehicleSize;
// other fields
public Vehicle(VehicleSize vehicleSize) {
this.vehicleSize = vehicleSize;
}
public VehicleSize getVehicleSize() {
return vehicleSize;
}
// rest of class
}
There is nothing mysterious about an enum, other than the number of different instances of it are known at compile time (and a few more things, but nothing scary).
To add this into a class, you can use it like any user defined type.
public class MyClass {
private MyEnum myEnum;
}

representing hierarchical relationship

Can you suggest me "How can I represent the hierarchical relationship through java class?"
you are welcomed to suggest other techniques.
For instance, User specifies that
"Room" belongs-to "Floor" and "Floor" belongs-to "Center"
I want to represent this relationship as Java class, and later want to retrieve this relationship.
-Pankesh
What you're talking about is standard object composition
'Belongs-to' and 'contains' are rather similar here. So for example:
public class Center
{
private List<Floor> floors;
...
public List<Floor> getFloors()
{
return this.floors;
}
}
public class Floor
{
private List<Room> rooms
...
}
public class Room
{
private String roomNumber;
...
}

How to define properties for Enum items

I have read the question Difference of Enum between java and C++? but I'm still confused.
I would like the following to return the related String:
public enum Checker {
EMPTY ("Empty"),
RED ("Red"),
YELLOW ("Yellow");
}
From what I have read, this should be possible. Just would like you to shed some light on it on how to implement it.
Short Answer
You need a constructor, a field and a getter.
Constructors
Enum types can have constructors, provided that their access level is either private or default (package-private). You can not directly call these constructors, except in the enum declaration itself. Similar to classes, when you define an enum constant without parameters, you actually call the default constructor generated by the compiler. E.g.
public enum King {
ELVIS
}
is equivalent to
public enum King {
ELVIS() // the compiler will happily accept this
}
And just like in classes, if you define an explicit constructor, the compiler will not insert a default constructor, so this will not compile:
public enum King {
ELVIS, // error, default constructor is not defined
MICHAEL_JACKSON(true)
;
private boolean kingOfPop;
King(boolean kingOfPop){this.kingOfPop = kingOfPop;}
}
This is a pretty good reference on enums that also explains the constructor issues.
Fields and Accessors
Enums are constants and are immutable as such. They can however define fields, that can have state. This is an awful practice, because developers will expect enums and their associated values to be constants, but you can still define a non-final field in an enum with getters and setters.
This is legal java code:
public enum Color {
RED("FF0000"),
GREEN("00FF00"),
BLUE("0000FF");
private String code;
public String getCode(){return code;}
public void setCode(String code){this.code = code;}
private Color(String code){this.code = code;}
}
But it enables evil code like this:
String oldBlue = Color.BLUE.getCode();
Color.BLUE.setCode(Color.RED.getCode());
Color.RED.setCode(oldBlue);
So in 99.99 % of cases: if you have fields in your enums, you should make them final and provide getters only. If the fields are not immutable themselves, provide defensive copies:
public enum Band {
THE_BEATLES("John","Paul","George","Ringo");
private final List<String> members;
public List<String> getMembers(){
// defensive copy, because the original list is mutable
return new ArrayList<String>(members);
}
private Band(String... members){
this.members=Arrays.asList(members);
}
}
Solution
In your case it's very simple: you just need a single field of type string (immutable), so initializing it in the constructor and providing a getter is perfectly ok:
public enum Checker {
EMPTY ("Empty"),
RED ("Red"),
YELLOW ("Yellow");
private final String value;
private Checker(final String value) {
this.value = value;
}
public String getValue() { return value; }
}
If the pattern holds, this works as well and eliminates the repetition:
public enum Checker {
EMPTY,
RED,
YELLOW;
public String getDescription(){
String name = name();
return ""+Character.toUpperCase(name.charAt(0))
+name.substring(1).toLowerCase();
}
}

Categories

Resources