How to store Enum class name and enum value in database - java

I have a class with different enums, for example:
class EligibilityRule{
ProductEligibility productEligibility;
CountryEligibility countryEligibility
}
enum ProductEligibility{
PRODUCT_X,
PRODUCT_Y
}
enum CountryEligibility{
US,
IN,
CN
..
}
I want to store these different enum class name and their value to database table called eligibility rule, and my table schema looks likes this,
String id => auto_increment id
String ruleType => enum class name (ex: ProductEligibility)
String ruleValue => enum value (ex: PRODUCT_X)
I am using JOOQ, in the past I had used forced type to just store the enum value. But, in this case I want to store enum class name and enum value. I also want to reconstruct the enum object when I query the records from db.
Are there any patterns I can follow or is there any functionality in JOOQ which I can extend to solve this problem?

JOOQ supports custom data types. This means that you can define a converter for your database field which is then automatically mapped to your custom type upon loading. The database field will still be a String, but the generated Record for the field will contain a Field<EligibilityRule>. This means that you do not have to explicitly store the class name.
To do this, you must register your converter in the code generator (taken from the above docs page):
<database>
<!-- Then, associate custom types with database columns -->
<forcedTypes>
<forcedType>
<!-- Specify the Java type of your custom type. This corresponds to the Converter's <U> type. -->
<userType>java.util.GregorianCalendar</userType>
<!-- Associate that custom type with your converter. -->
<converter>com.example.CalendarConverter</converter>
<!-- Add a Java regular expression matching fully-qualified columns. Use the pipe to separate several expressions.
If provided, both "expressions" and "types" must match. -->
<expression>.*\.DATE_OF_.*</expression>
<!-- Add a Java regular expression matching data types to be forced to
have this type.
Data types may be reported by your database as:
- NUMBER regexp suggestion: NUMBER
- NUMBER(5) regexp suggestion: NUMBER\(5\)
- NUMBER(5, 2) regexp suggestion: NUMBER\(5,\s*2\)
- any other form
It is thus recommended to use defensive regexes for types.
If provided, both "expressions" and "types" must match. -->
<types>.*</types>
</forcedType>
</forcedTypes>
</database>
See also the custom data type binding that JOOQ supports.
I see what you mean, in my case I am not creating new database field for each enum instead they will be stored as rule_type and rule_value(key/value) pair, where the key is the class name and the value is the enum value.
I see. Unfortunately, I do not think that it would be possible to do this in a type-safe manner. I believe this answer is pretty much what you're asking - a binding of a special type based on column value.
Since you are using enums however, you cannot have them extend a superclass as in the above answer (since all Enums implicitly extend java.lang.Enum and Java does not support multiple-inheritance). You might however try to slightly refactor your code and have all your enums implement some interface, i.e. :
enum ProductEligibility implements Rule {...};
enum CountryEligibility implements Rule {...};
With Rule being:
interface Rule { String getRuleType(); String getRuleValue(); }
And then creating a converter like in the example in the docs page or in the separate linked answer.
Of course, this also means that your Records would have a Field<Rule> field in them, not the specific type of the enum. If this is acceptable for you, it might be a possible way to go.
I did not get this part, Of course, this also means that your Records would have a Field<Rule> field in them, not the specific type of the enum.. Does this mean I will still store two fields in db, rule_type and rule_value with CustomConverter for each one of them?
No. You would still have only one converter, of type Converter<Object, Rule>. This converter would return either ProductEligibility or CountryEligibility, but it can't return both.
So, if your database table had something like:
eligiblity_rules
------------------
id user type value
234 223 com.foo.bar.ProductEligibility PRODUCT_Y
856 855 com.foo.bar.CountryEligibility US
Your converter would look something like this:
public Converter<Object, Rule> converter() {
return new Converter<Object, Rule>() {
#Override
public Rule from(Object t) {
// t here refers to the "value" db field above
if (checkIsProductEligibilityRule())
return ProductEligibility.fromValue(...);
else
return CountryEligibility.fromValue(...)
}
// Other converter methods
};
}
So in your JOOQ-based code, you would end up having:
EligibilityRuleRecord record = dslContext.selectFrom(ELIGIBILITY_RULE).where(...).fetchOne();
Rule rule = record.getValue();
Afterwards, if you want to use the specific rule type, you would need a check and a cast:
if (rule instanceof ProductEligibility) {
ProductEligibility peRule = (ProductEligibility) rule;
...
}
if (rule instanceof CountryEligibility) {
CountryEligibility ceRule = (CountryEligibility) rule;
...
}
...
The only reason for the type database field is for selecting the correct data. Unfortunately, the Java code does not know (at compile-time) what the type is going to be, hence you will need the class checks at runtime every time you wish to do know that field's specific type.

Related

Why would we need any type wirings other than those for queries?

In GraphQL Java implementation's document, type wiring is done as below, which contains one for the human query and one for the friends field of the Human type as highlighted.
I am wondering what is the use of the latter, the one for the friends field of the Human type.
I think we already return the a whole Human object, including the friends field, in the former type wiring using the StarWarsData.getHumanDataFetcher(), then why we need the latter?
Thanks!
The schema is as below:
The friendsfield is of type Character[]. When you return a certain type, fields that aren't of a built-in scalar type (such as String, which is built-in, vs. Character which isn't) require their own fetcher in order to be retrieved. You can, however, define a DTO that models the Human type and the smart graphql.schema.PropertyDataFetcher provided by graphql-java should retrieve the fields of your POJO, since it knows how to follow POJO patterns based on the field name.

Mapped column value to enum first argument

I have in DB String column with values
0101
0111
1110
I want create enum in my entity and add value.
public enum MyEnum{
NEW("0101","created new"),
SUCCESS("0111", "created success),
ERROR("1110", "created with error");
}
And I want mapped values from DB by first argument of MyEnum and get second argument in my code. Something like this:
hz.getMyEnum().value() // I need return created new or created success
I know that the question was about JPA – and the other answer states correctly, that JPA 2.1 does not support this kind of mapping... but jOOQ supports it through org.jooq.impl.EnumConverter without problems, see https://www.jooq.org/doc/3.10/manual/sql-execution/fetching/data-type-conversion/
unfortunately jpa currently (till 2.1) doesn't support mapping to enum scoped variables
You can either :
1- store the values as NEW,SUCCESS,ERROR instead of 0101,0111,1110
2- keep it as is
3- (inspired from Kovacs answer) you can create a #Converter <Enum,String> and insert the string variable name corresponding to the enum and vice versa ... the only thing to consider is that this converter will be tightly coupled to your enum

Java enum-alternative mapping

Trying to create my own shiny ORM system (not that important information), I'm currently struggling with java inheritance limits. Here is the concept:
public class UserDescriptor implements TableDescriptor {
public static final UserDescriptor INSTANCE = new UserDescriptor();
private UserDescriptor() {
}
public String getTableName() {
return "user";
}
// ======= Columns definition
public static final AbstractColumn<Integer> ID =
new IntegerColumn("id", AbstractColumn.Attribute.NOT_NULL);
public static final AbstractColumn<String> ALIAS =
new StringColumn("alias");
// ... and some more...
}
Hope it's clear enough. These are then used with static import like:
map = JDBCHelper.selectFirst(UserDescriptor.INSTANCE, Arrays.asList(ID, ALIAS));
where the list (2. param) is what I need to fetch from table defined by UserDescriptor. map variable holds custom map, which internally has signature similar to <AbstractColumn<T>, T> and method
public T getValue(AbstractColumn<T> col);
so I'm getting the value then type-safe
Integer id = map.getValue(ID);
String alias = map.getValue(ALIAS);
This concept is currently working, but:
TableDescriptor concept is a bit verbose. I have many tables and need many times to write twice the type and this long start of each column definition
public static final AbstractColumn<Integer>
This line is result of well-know java limitation - not possible to extend enum class. Otherwise the TableDescriptor would be abstract class with field AbstractColumn<T> defined by explicit constructor and every successor would be enum with columns defined within instances.
This would come with following advantages:
Possibility to make whole thing (conditions, returning columns definition, .....) more type-safe, eg. only enum of specific type can be listed in List parameter for select from single table,
better readability and basis for new developers,
getAllColumns functionality can be done without reflection.
This is unfortunately not possible, so you're now my last hope. I know enum inheritance stuff is on SO many times, but I already have already working solution and maybe it's possible to improve it some other way in this specific case..
What may be some kind of hint - these descriptors must now be int the API part of project to selects to be possible. I was struggling with the way I'd put it to impl. and in API I'll let only some enum listing only overview of the columns:
public enum UserTableColumns {
ID,
ALIAS
}
and map it somehow to UserDescriptor - then I'd be able to use in most cases only this enum, but I didn't figure out yet how this should work..
Current signature of selectFisrt method is following:
CustomResultMap selectFirst(TableDescriptor td, List<AbstractColumn<?>> cols);
and one possible modification would be to change List<AbstractColumn<?>> to some list of enum values, which will be mapped to TableDescriptor so I can check that the values are from single table.
Edit: clarification
I'll try to summarize what I understood from your question and the comments:
Your API should contain an enum like UserTableColumn as well as a method that currently looks like T get(AbstractColumn<T>) but should return the correct type based on the generic type of the column. Since AbstractColumn basically is meant to be an implementation detail you'd like to replace that with the enum, e.g. to get something like this (which won't compile): T get(UserTableColumn<T>).
(Please correct me if I made a mistake somewhere.)
The problem with that is that generics are a compile time tool, i.e. the compiler needs to know about the type that is being used. However, enum values can't have generic types and any parameter (e.g. ID(Integer.class)) would not be available at compile time since it's basically an instance (i.e. runtime) value.
Thus you'll need something like AbstractColumn<T> although that might be another class that only contains the generic type (and implements some interface). That probably requires some manual definition or the use of a preprocessor (have a look at how Hibernate does it for its criteria api).

How to format table values in vaadin?

If I have an object with BigDecimal property, I want to display it in a Table with a specific formatting: 2 fractions, and a "+" or "-" sign according to the amount.
Eg: +10.50, -3.20
How can this be achieved in a vaadin table? There is a method table.setConverter(..), but this would actually force to convert between eg a BigDecimal.class and a String.class. What I'm more after is just a view formatter that just displays the object data differently.
While using Table.formatPropertValue() for formatting table columns is a viable option, I strongly discourage from using this method when working with Vaadin 7. formatPropertValue() is the old Vaadin 6 way of formatting Table values. This method is still available in Vaadin 7 for downward compatibility. Using this method is problematic in several ways:
It is not typesafe. Since you only get a Property<?> as a parameter you first have to check for the concrete type of the property value.
You have to inherit from Table only to adapt the formatting of one or more columns. Class inheritance is definitely the wrong approach for adapting a class's behavior for one particular use case. If you have more than one such cases, you'll end up implementing a bunch of Table subclasses which later can't be easily interchanged.
You hard-wire conversion code (BigDecimal to String) to the concrete implementation of some UI component. That's bad for re-use. What if you need that conversion in some other place, say when you display a BigDecimal on a Label? You'd have to duplicate this code or somehow extract it into a separate class or method.
The last point is exactly what Vaadin 7 does for you: keep conversion logic separate from some concrete UI component. This is what the com.vaadin.data.util.converter.Converter interface is for. So, the OP was quite right in his/her first assumption: Table.setConverter() is the way to go with Vaadin 7. Converters are typesafe and allow for separation of concerns.
The objection that the Converter which can be set with Table.setConverter() only converts from BigDecimal to String is not justified in this case. Table.formatPropertValue() doesn't do anything different - it also converts to String. But this is obvious, a Table doesn't display anything other than String data in its columns. In fact, the default behaviour of Table is to call the toString() method on Property value types that it can't convert on its own.
For using Converters, see section 9.2.3 of the Book of Vaadin.
Override the protected method Table.formatPropertValue():
public class My_table
extends Table
{
#Override
protected String formatPropertyValue(final Object a_row_id,
final Object a_col_id,
final Property<?> a_property)
{
if (a_property.getType() == BigDecimal.class
&& null != a_property.getValue())
{
return "formatted-value";
}
return super.formatPropertyValue(a_row_id, a_col_id, a_property);
}
}
See Book of Vaadin section 5.16.6. Formatting Table Columns.
You have to write your own table class extending Table and override formatPropertyValue(Object rowId, Object colId, Property<?> property).
See section 5.15.6 in the book of Vaadin

JPA - Using null values in #DiscriminatorValue

I was wondering if I could use the DiscriminatorValue to set apart two subtypes in the following manner:
B extends A
#DiscriminatorValue(null)
A
#DiscriminatorValue("Some-Value")
B extends A
The point is that I want to check if there is a null value in some DiscriminatorType.Char column.
I tried writing "" (empty string) as the value and also null. Niether worked.
The DiscriminatorValue is normally set by the implementation, and you should only need to set it when the implementation cannot properly tell two classes apart, like having duplicate class names or very long class names.
For example, in Hibernate/Postgres, the default discriminator is the simple class name. The only time I have ever had to set it is in deeply nested classes that run on longer than the name limit in the database.
So, long story short, don't specify a discriminator value unless you must.
Annotation do not allow a null indicator, nor does the spec directly support it.
If you are using EclipseLink, you should be able to use a DescriptorCustomizer to add a null classIndicator mapping to the A's ClassDescriptor's inhertiancePolicy.

Categories