Replacing Enum constants with static variable fetched from table - java

Dealing with an old enum class which contains group of constants. A function inside enum class is defined to check if a passed constant is present in the enum or not.
Now there can be some constants that may be added to enum. If so it has to go through separate release process.
So we want to get rid of enum and get data from db or from a property file so that any new addition need not go through release.
But there is a problem with it. There are too many modules referring to the enum, hence demising enum will cause too many file changes.
Initial Enum class
Class enum Planets{EARTH,MARS,SATURN};
private static final Planets[] codes={EARTH,MARS,SATURN};
public static boolean isPlanetPresent(String str){//static Edited 19-09-2013
for(Palnets planet : codes){
if(planet.equals(str)){
return true;
}
return false;
}
With the above if we need to check whether NEPTUNE is part of Planets then we need to use Planets.isPlanetPresent("NEPTUNE") .
In order to minimize changes, I decided to retain the enum class but as a ordinary class.
A static array is declared inside the class and is loaded during runtime which reads data from a table in db.
Static alternative I thought of:
Class Planets{
private static String[] codes;
public Planets{
Spring IOC to connect to db and get the data and place it into codes array( EARTH,MARS,SATURN)
}
public static boolean isPlanetPresent(String str){
for(String planet : codes){
if(planet.equals(str)){
return true;
}
return false;
}
}
With the above implementation Planets.isPlanetPresent("NEPTUNE") need not be changed in other files.
My question is:
Is my implementation correct?
Are there any better alternative implementations?

Way 1
You could declare an entity (if you use an ORM) with static constant, something like this (with hibernate):
public class Planet {
public static final Planet SATURN = new Planet(1L, "SATURN");
public static final Planet MARS = new Planet(2L, "MARS");
// ...
private static final Planet[] VALUES = { SATURN, MARS /*, ...*/ }
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name", nullable = false)
private String name;
private Planet(final Long id, final String name) {
this.id = id;
this.name = name;
}
/**
* Simulates enum#values().
*
* #return list of declared values.
*/
public static Planet[] values() {
return VALUES.clone();
}
/**
* Simulates enum#valueOf(String).
*
* #return found {#link Planet} or null.
*/
#Nullable
public static Planet valueOf(final String name)
{
Planet result = null;
for (final Planet val : values()) {
if (val.getName().equals(name)) {
result = val;
break;
}
}
return result;
}
}
Way 2
Stick to an enum, and use DB "enumerated" datatype to ensure a db change when an enum value is added.

Related

Java nested POJO update based on dot annotation

I have a nested POJO structure defined something like this,
public class Employee {
private String id;
private Personal personal;
private Official official;
}
public class Personal {
private String fName;
private String lName;
private String address;
}
public class Official {
private boolean active;
private Salary salary;
}
public class Salary {
private double hourly;
private double monthly;
private double yearly;
}
I get updates from a service with dot annotaion on what value changed, for ex,
id change --> id=100
address change --> personal.address=123 Main Street
hourly salary change --> official.salary.hourly=100
This POJO structure could be 3-4 level deeps. I need to look for this incoming change value and update the corresponding value in POJO. What's the best way of doing it?
If you would like to create Java objects that allows you to edit fields. You can specify your object fields with the public/default/protected access modifiers. This will enable you to get and set fields such as personal.address or official.salary.hours
This approach is typically frowned upon as the object is no longer encapsulated and any calling methods are welcome to manipulate the object. If these fields are not encapsulated with getters and setters, your object is no longer a POJO.
public provides access from any anywhere.
default provides access from any package
protected provides access from package or subclass.
public class Employee {
public String id;
public Personal personal;
public Official official;
}
public class Personal {
public String fName;
public String lName;
public String address;
}
Here's a quick approach using reflection to set fields dynamically. It surely isn't and can't be clean. If I were you, I would use a scripting engine for that (assuming it's safe to do so).
private static void setValueAt(Object target, String path, String value)
throws Exception {
String[] fields = path.split("\\.");
if (fields.length > 1) {
setValueAt(readField(target, fields[0]),
path.substring(path.indexOf('.') + 1), value);
return;
}
Field f = target.getClass()
.getDeclaredField(path);
f.setAccessible(true);
f.set(target, parse(value, f.getType())); // cast or convert value first
}
//Example code for converting strings to primitives
private static Object parse(String value, Class<?> type) {
if (String.class.equals(type)) {
return value;
} else if (double.class.equals(type) || Double.class.equals(type)) {
return Long.parseLong(value);
} else if (boolean.class.equals(type) || Boolean.class.equals(type)) {
return Boolean.valueOf(value);
}
return value;// ?
}
private static Object readField(Object from, String field) throws Exception {
Field f = from.getClass()
.getDeclaredField(field);
f.setAccessible(true);
return f.get(from);
}
Just be aware that there's a lot to improve in this code (exception handling, null checks, etc.), although it seems to achieve what you're looking for (split your input on = to call setValueAt()):
Employee e = new Employee();
e.setOfficial(new Official());
e.setPersonal(new Personal());
e.getOfficial().setSalary(new Salary());
ObjectMapper mapper = new ObjectMapper();
setValueAt(e, "id", "123");
// {"id":"123","personal":{},"official":{"active":false,"salary":{"hourly":0.0,"monthly":0.0,"yearly":0.0}}}
setValueAt(e, "personal.address", "123 Main Street");
// {"id":"123","personal":{"address":"123 Main Street"},"official":{"active":false,"salary":{"hourly":0.0,"monthly":0.0,"yearly":0.0}}}
setValueAt(e, "official.salary.hourly", "100");
// {"id":"123","personal":{"address":"123 Main Street"},"official":{"active":false,"salary":{"hourly":100.0,"monthly":0.0,"yearly":0.0}}}

Using an argument as an interface item

In the program I am making, I am trying to get a formatted season name for a given season(formatted so it . I keep the formatted names in an interface, since if I were to use a map, it would be unnecessarily regenerated, since I don't make an instance of TeamBuilder
The Seasons interface:
public interface Seasons {
/*
* Contains a formatted list of seasons.
*
* An interface is being used as an alternative to using a Map in the
* TeamBuilder class, since calling parseTeam would have to build
* mappings for the seasons each time it
* was called. This way, the formatted name can simply be grabbed
*/
final String Skyrise = "Skyrise";
final String Toss_Up = "Toss%20Up";
final String Sack_Attack = "Sack%20Attack";
final String GateWay = "Gateway";
final String Round_Up = "Round%20Up";
final String Clean_Sweep = "Clean%20Sweep";
final String Elevation = "Elevation";
final String Bridge_Battle = "Bridge%20Battle";
final String Nothing_But_Net = "Nothing%20But%20Net";
final String Starstruck = "Starstruck";
final String In_The_Zone = "In%20The%20Zone";
final String Turning_Point = "Turning%20Point";
}
The problem comes when I try to grab these seasons. My TeamBuilder class takes in an argument(String season), which is unformatted. My question is, is there any way that I can use a String argument for a method to get a specific item from an interface? This is the most preferable to using a HashMap, which would needlessly regenerate the same information
All these classes can be found on the Github page for this project.
If you want to do it in a typed way, you can use Enum for this:
enum Season{
Skyrise,Toss_Up, Sack_Attack;
#Override
public String toString() {
switch(this){
case Skyrise: return "Skyrise";
case Toss_Up: return "Toss%20Up";
case Sack_Attack: return "Sack_Attack";
default: return "";
}
}
}
public class main{
public static void printSeason(Seasons seasons){
System.out.println(seasons);
}
public static void main(String[] args) {
Seasons e = Seasons.Skyrise;
printSeason(e);
System.out.println(e);
}
}
Since the compiler internally invokes the toString(), you can pass the argument as a Seasons or a String like my example.
And if you still want to use a map without "unnecessarily regenerated" you can use a static field with static initializer like this:
class Seasons {
private static Map<String,String> map = new HashMap<>();
static {
map.put("Skyrise", "Skyrise");
map.put("Toss_Up", "Toss%20Up");
}
public static String getFormatted(String key){
return map.getOrDefault(key,"");
}
}
class main{
public static void main(String[] args) {
System.out.println(Seasons.getFormatted("Skyrise"));
}
}
Just to integrate on Snoob answer you can have enum with fields, so:
enum Season
{
Skyrise("Skyrise"),
Toss_Up("Toss%20Up"),
Sack_Attack("Sack%20Attack")
;
public final String fancyName;
private Season(String fancyName)
{
this.fancyName = fancyName;
}
}
You really have all the benefits without any drawback.

Creating an abstract base class for handling different type of enums

Currently I have several enums defined over several classes. They all look similar to the one shown below:
public class ApaMessage {
private String apaMessage;
private final int FIXED_LENGTH_SIZE=39;
public enum ApaFields {
FIELD1(ApaUtils.ApaFieldTypes.POSITION_BASED, null, "field1", 2, 3, false, false),
private final ApaUtils.ApaFieldTypes type;
private final String ApaName;
private final String jsonName;
private final int start;
private final int finish;
private boolean required = false;
private boolean withDelimiter = false;
ApaFields(ApaUtils.ApaFieldTypes type, String ApaName, String jsonName, int start, int finish, boolean required, boolean withDelimiter) {
this.type = type;
this.ApaName = ApaName;
this.jsonName = jsonName;
this.start = start;
this.finish = finish;
this.required = required;
this.withDelimiter = withDelimiter;
}
}
There is also a method defined in ApaMessage:
private HashMap<String,Object> getApaJsonFieldsAndValues() {
HashMap<String, Object> jsonApaData = new HashMap<String, Object>();
for (ApaFields field : ApaFields.values()) {
jsonApaData.put(field.jsonName, getApaFieldValue(field));
}
return jsonApaData;
}
The problem is although there isn't a lot of code, I will soon have 10-20 of these enums. I would like to create an abstract base class where the HashMap method, and other similar methods can be part of. The base class should accept an ApaFields enum and other enums and do what the getApaJsonFieldsAndValues does. The problem is, how can the base class access the passed enum values and the internal fields such as jsonName to do the loop?
I have tried different approaches but the main problem is that the base class cannot seem to access the values. Is there any way around this? Alternatively, is there a better approach? Thanks
EDIT:
Basically I would like something like this in the base class. Note the below doesn't compile.
public abstract class ApaRequestMessage {
private Class<? extends Enum<?>> apaRequestMessageFields;
private String apaMessage;
public <T extends Enum<T>> void ApaRequest(Object apaRequestFields, String apaMessage) {
apaRequestMessageFields = (Class<? extends Enum<?>>) apaRequestFields;
this.apaMessage = apaMessage;
for (Field field: apaRequestMessageFields.values()) {
//this doesn't work because it cannot access the values of apaRequestMessageFields
}
}
}
And then call the base method as follows, although not sure if this is correct, where ApaFields is the inner enum defined above.
ApaRequest(ApaFields.class, somestringmessage);
I came across something similar when trying to define a db schema using enums as columns in the table. I eventually took this route.
Define a base class with sufficient generic signature to ensure the enum is properly built.
public class Table<Column extends Enum<? extends Column>> {
// Name of the table.
protected final String tableName;
// All of the columns in the table. This is actually an EnumSet so very efficient.
protected final Set<Column> columns;
/**
* The base interface for all Column enums.
*/
public interface Columns {
// What type does it have in the database?
public Type getType();
}
// Small list of database types.
public enum Type {
String, Number, Date;
}
public Table(String tableName,
Set<Column> columns) {
this.tableName = tableName;
this.columns = columns;
}
}
Now extend this for each table - here is a simple VersionTable:
public class VersionTable extends Table<VersionTable.Column> {
public enum Column implements Table.Columns {
Version(Table.Type.String),
ReleaseDate(Table.Type.Date);
final Table.Type type;
Column(Table.Type type) {
this.type = type;
}
#Override
public Type getType() {
return type;
}
}
public VersionTable() {
super("Versions", EnumSet.allOf(Column.class));
}
}
Now you have all of the core functionality in the base class and all the sub-classes need to do is implement the interface on the enum.
I realise this does not address the issue of duplicated bolierplate code in all of your enums but it does move alomst all of it elsewhere.

Java: Unable to use EnumSet within an Enumeration : Initialization error : Tech Research Talent Tree example

Error:
...
Caused by: java.lang.ExceptionInInitializerError
...
Caused by: java.lang.ClassCastException:
class com.evopulse.ds2150.TechTrees$BuildingTechTree
not an enum
at java.util.EnumSet.noneOf(Unknown Source)
at java.util.EnumSet.of(Unknown Source)
at com.evopulse.ds2150.TechTrees$BuildingTechTree.<clinit>(TechTrees.java:38)
Here is a snippet of my enumeration
public enum BuildingTechTree {
//Name SoftName Requirements
NONE ("NULL", null),
--> This next line is where it crashes
BARRACKS ("Barracks", EnumSet.of(NONE),
WALLS_SANDBAGS ("Sandbag wall", EnumSet.of(NONE),
POWERPLANT ("Power plant", EnumSet.of(BARRACKS)),
GUARDTOWER ("Guard Tower", EnumSet.of(BARRACKS));
Replacing EnumSet.of(NONE) and EnumSet.of(BARRACKS) with null, lets initialization work, but breaks my code, due to missing data structure... obviously, but I did it to test the rest of my code wasn't somehow the cause.
Removing EnumSet.of(NONE) and replacing with just NONE, and the same for BARRACKS, and changing all related variables, constructor, and methods, that didn't work either... (and even couldn't use the contains.all, since is wasn't "applicable to my changed variable"... )
I extended this example, using the second implementation:
https://gamedev.stackexchange.com/a/25652/48573
I also tried retracing my steps by copying the example verbatim. added
private static Set<BuildingTechTree> techsKnown;
techsKnown = (BuildingTechTree.BIODOME);
test = TechTrees.researchTech(techsKnown);
to another class to be called from for testing initialization. and had to change
public boolean researchTech(BuildingTechTree tech) {
to static
This resulted in the same "in not an enum" error. I don't have any rep, to comment on his answer to point out the initialization error...
Added info for both current answers, as both solutions cause the same new error:
public class TechTrees {
private static Set<BuildingTechTree> techsKnown;
public TechTrees() {
techsKnown = EnumSet.of(BuildingTechTree.NONE); //Using this
techsKnown = EnumSet.noneOf(BuildingTechTree.class); //Or this
}
public static boolean researchTech(BuildingTechTree tech) {
if (techsKnown.containsAll(tech.requirements)) { //Causes null pointer
return true; //exception # techsKnown
}
return false;
}
Your declaration structure is so clever it's a shame it doesn't work. But EnumSet apparently needs the enum to be fully initialized first. It tries to fetch the array of constants from the enum so that, among other things, it knows how much space is needed for its internal bitset.
Here's one workaround. It uses a helper method that creates an ordinary set (HashSet) first, and then, in a static initialization block, it iterates the enum constants and replaces all the sets with EnumSets.
public enum BuildingTechTree {
// Named constants
//Name SoftName Requirements
NONE ("NULL", null),
BARRACKS ("Barracks", setOf(NONE)),
WALLS_SANDBAGS ("Sandbag wall", setOf(NONE)),
POWERPLANT ("Power plant", setOf(BARRACKS)),
GUARDTOWER ("Guard Tower", setOf(BARRACKS));
private final String softName;
private Set<BuildingTechTree> requirements;
private BuildingTechTree(String softName, Set<BuildingTechTree> requirements) {
this.softName = softName;
this.requirements = requirements;
}
private static Set<BuildingTechTree> setOf(BuildingTechTree... values) {
return new HashSet<>(Arrays.asList(values));
}
static {
for (BuildingTechTree v : values()) {
if (v.requirements == null) {
v.requirements = EnumSet.noneOf(BuildingTechTree.class);
} else {
v.requirements = EnumSet.copyOf(v.requirements);
}
}
}
}
You have a chicken and egg problem. You could refactor your enum to something like this:
public enum BuildingTechTree {
NONE("NULL"),
BARRACKS("Barracks"),
WALLS_SANDBAGS("Sandbag wall"),
POWERPLANT("Power plant"),
GUARDTOWER("Guard Tower");
static {
NONE.trees = EnumSet.noneOf(BuildingTechTree.class);
BARRACKS.trees = EnumSet.of(NONE);
WALLS_SANDBAGS.trees = EnumSet.of(NONE);
POWERPLANT.trees = EnumSet.of(BARRACKS);
GUARDTOWER.trees = EnumSet.of(BARRACKS);
}
private String name;
private Set<BuildingTechTree> trees;
private BuildingTechTree(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Set<BuildingTechTree> getTrees() {
return Collections.unmodifiableSet(trees);
}
}
EDIT:
regarding your second problem: you're accessing a static variable, from a static method. But this variable is initialized when the constructor of the class has been called (which is a huge design problem). Don't use non-final static fields. And don't initialize static fields from instance methods or constructors. That doesn't make sense. You don't set the color that all cars should have when constructing a car. Initialize your static fields statically:
public class TechTrees {
private static final Set<BuildingTechTree> TECHS_KNOWN =
EnumSet.of(BuildingTechTree.NONE);
public static boolean researchTech(BuildingTechTree tech) {
return TECHS_KNOWN.containsAll(tech.requirements));
}
}

Webservice increment variable for id use singleton/synchronize

I am implementing a webservice witch is used to attack one DB.
i need to generate ID for objects that i store and i don't know what's the best way to do it.
i need to increment a INT.
Obviously the webservice must to be used for so much people and maybe various at same time.
so, what's is a good solution?
singleton/synchronize??
i think is the only way i know, maybe there are others better.
if u can show me one example it will be very appreciated.
thanks in advance!
Synchronize has horrible overhead. If all you need is an incremental counter, you can use AtomicLong's incrementAndGet(). Put the AtomicLong in a Singleton to have a server-wide access.
Edit: Some code example:
import java.util.concurrent.atomic.AtomicLong;
public class AtomicIdGenerator
{
private static class SingletonHolder
{
public static final AtomicIdGenerator instance = new AtomicIdGenerator();
}
public static AtomicIdGenerator getInstance()
{
return SingletonHolder.instance;
}
private AtomicLong mIdGenerator = null;
private AtomicIdGenerator()
{
mIdGenerator = new AtomicLong();
}
private AtomicLong getGenerator()
{
return mIdGenerator;
}
public long getNewId()
{
return getGenerator().incrementAndGet();
}
}
Usage example is simply:
long tNewId = AtomicIdGenerator.getInstance().getNewId();
This will be thread-safe, and without any overhead from synchronization. If you foresee yourself handling lots of concurrent use cases in the future, the java.util.concurrent package provides lots of battle-proven implementations for your use cases.
Use synchronize block to achieve this. In synchronized block only one thread can enter inside it.
JVM guarantees that Java synchronized code will only be executed by one thread at a time.
You can do something like this. I've done it a while back, it was based on PostgreSql and iBatis, but you can get the idea.
public class Sequence implements Serializable {
private static final long serialVersionUID = 7526471155622776147L;
private String name = null;
private int nextId = 0;
public Sequence () {
}
public Sequence (String name, int nextId) {
this.name = name;
this.nextId = nextId;
}
public final String getName () {
return name;
}
public final void setName (String name) {
this.name = name;
}
public final int getNextId () {
return nextId;
}
public final void setNextId (int nextId) {
this.nextId = nextId;
}
}
public class SequenceSqlMapDao extends SqlMapClientDaoSupport implements SequenceDao {
/**
* This is a generic sequence ID generator that is based on a database
* table called 'SEQUENCE', which contains two columns (NAME, NEXTID).
* <p/>
* This approach should work with any database.
*
* #param name The name of the sequence.
* #return The Next ID
* #
*/
public final synchronized int getNextId(String name) {
Sequence sequence = new Sequence(name, -1);
//Sequence sequence = new Sequence();
sequence = (Sequence) getSqlMapClientTemplate ().queryForObject("getSequence", sequence);
if (sequence == null) {
try {
throw new IllegalArgumentException("Error: SHOOT! A null sequence was returned from the database (could not get next " + name + " sequence).");
} catch (Exception ex) {
Logger.getLogger(SequenceSqlMapDao.class.getName()).log(Level.SEVERE, null, ex);
}
}
Object parameterObject = new Sequence(name, sequence.getNextId() + 1);
getSqlMapClientTemplate ().update("updateSequence", parameterObject);
int nextId = sequence.getNextId();
parameterObject = null;
sequence = null;
return nextId;
}
}
If nothing else this is pretty database agnostic. You'd still have to expose the method in your webservice.
PS - I forgot where I got this from, otherwise I'd give credit to proper source.

Categories

Resources