omnifaces / omnipersistence

Utilities for JPA, JDBC and DataSources
Other
31 stars 12 forks source link

Added functionality for enhanced @Enumerated mapping. #13

Closed skuntsel closed 6 years ago

skuntsel commented 6 years ago

Added basic functionality for enhanced enum mapping that empowers standard JPA @Enumerated mapping via @JpaEnum annotation.

When used in conjunction with @Enumerated(ORDINAL) @JpaEnum allows developer to specify fieldName of type Integer/int of application enum that will be persisted to the database, instead of the standard ordinal of a particular enum.

When used in conjunction with @Enumerated(STRING) @JpaEnum allows developer to specify fieldName of type String of application enum that will be persisted to the database, instead of the standard name of a particular enum.

This allows to create more robust applications with the ability to modify/add/delete enum instances during application development, thus alleviating the vulnerabilities of standard JPA @Enumerated.

Its usage is as follows:

@JpaEnum(fieldName = "id")
public enum ProductStatus {

    IN_STOCK(1), OUT_OF_STOCK(10), DISCONTINUED(20);

    private int id;

    private ProductStatus(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

}

and

@JpaEnum(type = EnumType.STRING, fieldName = "code")
public enum UserRole {

    USER("USR"), EMPLOYEE("EMP"), MANAGER("MGR");

    private String code;

    private UserRole(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }

}

with

@Entity
public class Product extends GeneratedIdEntity<Long> {

    private static final long serialVersionUID = 1L;

    @Enumerated
    private ProductStatus productStatus;

    @ElementCollection
    @Enumerated(STRING)
    private Set<UserRole> userRoles = new HashSet<>();

    public ProductStatus getProductStatus() {
        return productStatus;
    }

    public void setProductStatus(ProductStatus productStatus) {
        this.productStatus = productStatus;
    }

    public Set<UserRole> getUserRoles() {
        return userRoles;
    }

    public void setUserRoles(Set<UserRole> userRoles) {
        this.userRoles = userRoles;
    }

    public void addUserRole(UserRole userRole) {
        userRoles.add(userRole);
    }

}

With such setup persistence provider will save to the database the status as either 1, 10 or 20 (as opposed to the default 0, 1 or 2 otherwise) and role as either USR, EMP or MGR (as opposed to default USER, EMPLOYEE or MANAGER otherwise).

This may be evolved even further with another, yet to be done, annotation @JpaEnumSpecifics that will define the correlation with the database lookup table for each enum used and will do, among others, the following:

BalusC commented 6 years ago

Great addition. I'm only a bit torn on the name @JpaEnum.

How about @EnumMapping?

skuntsel commented 6 years ago

That sounds really good! It was definitely intended to serve as a working title, as I didn’t have much chance to contemplate about its name. Until we have first class support for such functionality from the spec this is our best bet. It puzzles me, though, why it hasn’t yet paved its way into the specification. We also need to add extra annotation (nested or top-level) to control correspondence with the database. It would feel natural to either map the database table as a source for enum values, or, preferrably, reflect changes in enum code in the database table.

пн, 23 апр. 2018 г. в 21:02, Bauke Scholtz notifications@github.com:

Great addition. I'm only a bit torn on the name @JpaEnum.

How about @EnumMapping?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/omnifaces/omnipersistence/pull/13#issuecomment-383668080, or mute the thread https://github.com/notifications/unsubscribe-auth/Aeq5DGauSTsfi4BVzj2m86IQDEDdHqWgks5trhdKgaJpZM4Tf-me .