Table as an enum. Is it possible? - java

How can I a map static table (which is not expandable) to an enum in Java and bind this table to another one?
For example, I have simple calculator web app (spring web MVC + hibernate) with one table (results of user's calculations) which has the following fields: id (PK), leftOperand, operation, rightOperand, result.
I would like to create a new static table (I mean for basic arithmetic operations like PLUS, MINUS, DIVIDE, MULTIPLY) with 2 fields: id(PK) and operation, and map this table to enum in Java.
So how can I bind these two tables (using operation field)?
Some pseudo-code is greatly appreciated.
Note that I do not need to create a hibernate entity for the static table. Just enum.

As with classes, you can add properties to enums like so:
public enum MyEnum {
PLUS(1, "something"),
MINUS(2, "something");
private final int id;
private final String string;
private MyEnum(int id, String string){
this.id = id;
this.string = string;
}
public int getId(){
return id;
}
public String getString(){
return string;
}
}
Assuming the 'opreration' field matches the enum's name, you can do the following:
MyEnum enumValue = MyEnum.valueOf(map.get("operation"));

I think you don't need static table for operation values. Just change operation field type to enum and use #Enumerated.
enum Operation {
PLUS, MINUS;
}
#Entity
public class Calculation {
private String leftOperand;
#Enumerated(EnumType.STRING)
private Operation operation;
private String rightOperand;
}

Related

Adding properties to enums in JOOQ

We have been moving away from hibernate to jooq for months now. Pattern we would often do in Hibernate would be writing a custom enum like this...
public enum HBMCapacityType {
Accepting("Accepting until end of day", true),
Limited("Limited until end of day", true),
AtCapacity("At Capacity until further notice",false);
private final String description;
private final boolean userOverridable;
HBMCapacityType(String description, boolean userOverridable) {
this.description = description;
this.userOverridable = userOverridable;
}
public String getDescription() {
return this.description;
}
public boolean isUserOverridable() {
return this.userOverridable;
}
}
Then we are able to use this a column in our hibernate domain objects
#Enumerated(EnumType.STRING)
#Type(type = "pg_enum")
#Column(name = "capacity_type", nullable = false, columnDefinition = "capacity_type")
private HBMCapacityType capacityType;
This is convenient as we can call capacityType.getDescription() when rendering to to the GUI. We have this nice 1:1 mapping of enum types to a description we can use in the GUI. Sometimes we have multiple getters like this say one for description and a few booleans which characterize behaviour associated with that enum. The property isUserOverrideable would be an example of this.
Now looking at JOOQ: since this was defined as an enum in postgres JOOQ automatically generates a type like this...
/**
* This class is generated by jOOQ.
*/
#SuppressWarnings({ "all", "unchecked", "rawtypes" })
public enum CapacityType implements EnumType {
Accepting("Accepting"),
Limited("Limited"),
AtCapacity("AtCapacity");
private final String literal;
private CapacityType(String literal) {
this.literal = literal;
}
#Override
public Catalog getCatalog() {
return getSchema().getCatalog();
}
#Override
public Schema getSchema() {
return Wastecoordinator.WASTECOORDINATOR;
}
#Override
public String getName() {
return "capacity_type";
}
#Override
public String getLiteral() {
return literal;
}
/**
* Lookup a value of this EnumType by its literal
*/
public static CapacityType lookupLiteral(String literal) {
return EnumType.lookupLiteral(CapacityType.class, literal);
}
}
I guess your question is about how to add custom properties to jOOQ generated enums? There are multiple approaches:
Using a custom code section
One way to achieve the same functionality is by adding a custom code section as described here. You'll add a generateEnumClassFooter() method to your own JavaGenerator subclass, and generate the necessary code there. Unlike in your original code, you can't modify the properties of enum values, so you'll just have to switch over this, instead.
Move the logic outside of the enum
You can always just write a static utility of the form
public static boolean isUserOverridable(HBMCapacityType type) {
return switch (type) { ... };
}
It's less object oriented, but maybe, that doesn't matter all that much?
Keep 2 separate enums
You don't have to use jOOQ's enum. You can translate it to your own hand-written enum and attach an EnumConverter to your generated code to map between the jOOQ enum type and yours.

How to make Morphia set the value of a field as the value returned by a function call?

I'm implementing the "auto-increment" id using strategy described here:
http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/
Basically the value of the seqId field is set by calling an utility function that updates the counter on an auxiliary collection and returns the incremented value. Sounds great.
My issue is in mapping this to be used with Morphia. The tutorial suggests performing the insert (such as in the shell) like so:
db.users.insert(
{
seqId: getNextSequence("userid"),
name: "Sarah C."
}
I'm basically looking to do something like setting the POJO seqId field to something that Morphia will translate into an insert like the one above when I invoke save().
My POJO looks like this:
#Entity
public class User {
#Id
private Long id;
// THIS IS THE FIELD I WANT TO AUTO-INCREMENT
private Long seqId;
private String name;
...
}
The question is: How to make Morphia set the value of a field as the value returned by a function call?
I looked into using the #PrePresist annotation to perform this function call and getting the value, then setting it in the +_id field. That has several drawbacks such as making multiple calls to MongoDB instead of just one, and also the fact that my model objects don't have a reference to the datastore and I'd rather not mix up the concerns.
Is this possible? Any suggestions?
I'm on MongoDB 2.6.6 using the latest Java drivers.
Thanks!
PS: I'm aware that auto-increment is not recommended in large environments. I need it anyways for this specific scenario.
I'll describe the solution that's working for us quite well. Note that this supports auto increments on the class level and a subset of it — so you can count users or admin-users (user with an admin enum or whatever).
This contains the current value for each auto increment field, it's basically a reference:
#Entity(noClassnameStored = true)
public class AutoIncrementEntity {
#Id
protected String key;
protected Long value = 1L;
protected AutoIncrementEntity() {
super();
}
/**
* Set the key name — class or class with some other attribute(s).
*/
public AutoIncrementEntity(final String key) {
this.key = key;
}
/**
* Set the key name and initialize the value so it won't start at 1.
*/
public AutoIncrementEntity(final String key, final Long startValue) {
this(key);
value = startValue;
}
public Long getValue() {
return value;
}
}
In your persistence service, you could use the following to set / create the auto increment automatically:
public <E extends BaseEntity> ObjectId persist(E entity) {
// If it's a user and doesn't yet have an ID, set one; start counting from 1000.
if ((entity instanceof UserEntity) && (((UserEntity) entity).getUserId() == null)) {
((UserEntity) entity).setUserId(
generateAutoIncrement(entity.getClass().getName(), 1000L));
}
// Additionally, set an ID within each user group; start counting from 1.
if ((entity instanceof UserEntity) && (((UserEntity) entity).getRoleId() == null)) {
((UserEntity) entity).setRoleId(
generateAutoIncrement(entity.getClass().getName() + "-" + entity.getRole(), 1L));
}
mongoDataStore.save(entity);
return entity.getId();
}
/**
* Return a unique numeric value for the given key.
* The minimum value, set to 1 if nothing specific is required.
*/
protected long generateAutoIncrement(final String key, final long minimumValue){
// Get the given key from the auto increment entity and try to increment it.
final Query<AutoIncrementEntity> query = mongoDataStore.find(
AutoIncrementEntity.class).field("_id").equal(key);
final UpdateOperations<AutoIncrementEntity> update = mongoDataStore
.createUpdateOperations(AutoIncrementEntity.class).inc("value");
AutoIncrementEntity autoIncrement = mongoDataStore.findAndModify(query, update);
// If none is found, we need to create one for the given key.
if (autoIncrement == null) {
autoIncrement = new AutoIncrementEntity(key, minimumValue);
mongoDataStore.save(autoIncrement);
}
return autoIncrement.getValue();
}
And finally your entity:
#Entity(value = "user", noClassnameStored = true)
public class UserEntity extends BaseEntity {
public static enum Role {
ADMIN, USER,
}
private Role role;
#Indexed(unique = true)
private Long userId;
private Long roleId;
// Role setter and getter
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
}
There's nothing specific going on in the entity. All the logic is handled by the persistence service. I'm not using the #PrePersist, because you'd then need to put the persistence service into the entity, which doesn't sound like a good idea.

Replacing Enum constants with static variable fetched from table

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.

How to write Nested Enum Code For the Data Bases and their tables and columns corrosponding

i am developing my project in which a large data base which has no of data bases and the tables, columns have
so my plan is to do somthing like if in future i have to change my database name or table name or columns name so i make changes only one place and all the changes done automatically where the DB name table or columns name has been used.
then i have to decided using enum for that hence enum should be nested and each property can have its string value so that only changes in the string value can change its all places where it has been used
so please help me some buddy to give me some sample of code samll code by which i can do it for my database
eg DATABASE->TABLE->COLUMNS
public enum DATABASE
{
//
}
i want enum sample code for database and nested enums for their tables and one of its nested enum for their columns please help me...!!!
i have tried it to find it but not got some thing usefull
ok i got my answer
here is
public enum DATABASE
{
DB1(TABLE.TBL1, TABLE.TBL2);
private final TABLE[] tblArray;
private DATABASE(TABLE... tables)
{
tblArray = tables;
}
public TABLE[] getTables()
{
return tblArray;
}
}
public enum TABLE
{
TBL1(COLUMN.CLMN1, COLUMN.CLMN2), TBL2(COLUMN.CLMN2);
private final COLUMN[] clmnArray;
private TABLE(COLUMN... columns)
{
clmnArray = columns;
}
public COLUMN[] getColumns()
{
return clmnArray;
}
}
public enum COLUMN
{
CLMN1, CLMN2;
}
actually i am not perfect in enum so please tell me how to access the DATABASE , TABLE and COLUMN means if i want DB1->TB1->CLMN2 so how to write code ...
It is not with enums, but I think what you want:
public abstract class DATABASE
{
public static class TABLE_ONE
{
public static final String NAME = "TableOne";
public static final String COL_ONE = "COLUMN_ONE";
public static final String COL_TWO = "COLUMN_TWO";
}
}
You can use it like DATABASE.TABLE_ONE.COL_ONE and so on.
Why I think this is dangerous: If you change Constants here, you'll have to handle DB-Updates also and mind people upgrading from one version of your software to another. So be careful!
you can try like this:
public enum DATABASE
{
DB1(TABLE.TBL1, TABLE.TBL2);
private final TABLE[] tblArray;
private DATABASE(TABLE... tables)
{
tblArray = tables;
}
public TABLE[] getTables()
{
return tblArray;
}
}
public enum TABLE
{
TBL1(COLUMN.CLMN1, COLUMN.CLMN2), TBL2(COLUMN.CLMN2);
private final COLUMN[] clmnArray;
private TABLE(COLUMN... columns)
{
clmnArray = columns;
}
public COLUMN[] getColumns()
{
return clmnArray;
}
}
public enum COLUMN
{
CLMN1, CLMN2;
}

"ChoiceField" (or: a better JPA Enum) in Play?

I'm very much used to the Django 'choices' option for a model field:
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
That allows, for a model field, to easily match a database value with a (representation) string. And works with whatever sql type is chosen (Char, Int...)
In JPA that's not possible; you can make an Enum: but only use its ordinal or string. I find that overly limiting and complicated.
Is there in Play! something similar to the Django choices, in particular to be used with the CRUD?
Or at least a pattern for the CRUD than just declare a simple String or int for the model field?
Related:
How to use enums with JPA
Map enum in JPA with fixed values?
play! framework ENUM and Groovy problem
I don't understand your problem with Enum, you can map enum with JPA like this
#Enumerated(EnumType.STRING)
public GenderChoice genderChoice;
an use the enum in your code. Is this not enough ?
Based on #SebCesbron comment this is the kind of pattern I'm using now...
#Required
#Enumerated(EnumType.STRING)
public MyEnumType myenum;
public enum MyEnumType {
ENUMONE ("label one", 1),
ENUMTWO ("label two", 2);
String label;
Int value;
CastType(String label, Int value) {
this.value = value;
this.label = label;
}
#Override
public String toString() {
return this.label;
}
public Int getValue() {
return this.value;
}
public String getLabel()
{
return label;
}
}
Using EnumType.STRING the database will contain the enum item name - overriding toString does not affect that, because JPA uses name() which is final.
So wrt to my precise usecase and question:
#Required
#Enumerated(EnumType.STRING)
public GenderEnum myenum;
public enum GenderEnum {
M ("Male"),
F ("Female");
String label;
CastType(String label) {
this.value = value;
}
#Override
public String toString() {
return this.label;
}
}

Categories

Resources