使用

一般而言,Java 的实体(Bean/Pojo)很少涉及“枚举(Enum)”类型,例如男女,分别用 int 表示 1= 男/2=女 就好了。Bean 写法如下。

private Integer sex;public Integer getSex() {reutrn sex;
}public void setSex(Integer sex) {this.sex = sex;
}

这是最正常不过了。但是,为了提高语义程度,我们希望把枚举的概念利用起来,那样程序代码的好处是更清晰了。使用枚举类型,是这样子的。

/*** 性别 0=未知/1=男/2=女*/
private Gender gender;public Gender getGender() {return gender;
}public void setGender(Gender gender) {this.gender = gender;
}

必须承认,为了换取可读性和语义性,那是有代价的,它会适当增加你的代码复杂度。但实际上,笔者觉得这是一个更细致深入的建模过程,抛弃掉以往那种定义常量的方式。

public static interface Gender {public static final int MALE  = 1;public static final int FEMALE= 2;
}

而采用 Java Enum:

import com.ajaxjs.framework.IntegerValueEnum;/*** 性别* * @author Frank Cheung<sp42@qq.com>*/
public enum Gender implements IntegerValueEnum {/*** 未知*/UNKNOW,/*** 男*/MALE,/*** 女*/FEMALE;@Overridepublic Integer getValue() {return ordinal();}
}

序列化与反序列化

这仅仅是 Java 层面的,如果涉及“序列化与反序列化”,也就是考虑:数据库与 Json 两处地方,该如何保存枚举呢?

首先数据库仍旧不变,还是保持 int/string。虽然 MySQL 支持 enum 类型字段,但为跨数据库而言,不考虑特殊类型的字段去使用。存储方面照旧,而问题在于读取的时候,怎么把 int/string 变为 Java 的枚举类型。

其二,输出 Json,怎么把 Java 的枚举类型变为 Json 输出呢?

综上所述,解决的一个思路就是,凡是遇到实体中的枚举类型,就作适当的转换,跟以前 Integer/String/Boolean 类型针对性处理的手法一样。当然那需要我们额外的操作,也就是前面所说的“代价”,你要在你的 ORM 框架(如 Mybatis)或者 Json 序列库(Jackson)中,当遍历 Bean 各字段时候,处理好 Enum 类型。

虽然不同框架的遍历切入的方法不一样,要看它具体如何开放出来,但是针对枚举的转换却是可以共性的。这点我们最后再讲。

如何定义枚举

既然我们说要识别枚举、处理枚举,那么需要将枚举类用一个接口简单标识一下,说明它是为 Bean 服务。我们知道,Java 中的枚举可以实现接口(但不能继承)。于是设计一个 BaseEnmu,表示,POJO 中可以读取的枚举,以及可以获取枚举值,

import java.io.Serializable;/*** POJO 中可以读取的枚举* * @author Frank Cheung<sp42@qq.com>**/
public interface BaseEnmu {Serializable getValue();
}

其实每个枚举类都继承 Enum——要看它是不是枚举,可以简单用 instanceOf Enum 一下,但为了更方便的识别,获取 value 值,最好还是设置一个 BaseEnmu 接口。

关于枚举值,就是保存到数据库或者输出到 Json 的那个值。不是方便人类阅读的(例如 0/1……),——在 Java 中使用枚举才是方便阅读的(例如 Male/Female……)。所以它肯定可以返回一个值,即 Serializable getValue();Serializable 类型的用意是兼容了 Number/String 的值。

如何安排值?一般是 MALE(1), FEMALE(2),甚至不写,用系统索引序号也可以。至于 String 类型也行,看你需求。使用系统索引序号有个问题,下面会讲。

当然,除了值你还可以在枚举中加入丰富的内容,相当于横向扩充说明,这就有点像 Java 程序里面的数据字典了,也可以被其他代码所引用。例如这个 Status 笔者加入的 desc 说明。

/*** 实体状态 这是最通用的状态,供参考使用* * @author Frank Cheung<sp42@qq.com>**/
public enum Status implements IntegerValueEnum, DescEnum {/*** 已上线/显示/启动/已激活*/ONLINE(1, "上线"),/*** 已下线/不显示/关闭/禁用/不激活*/OFFLINE(0, "下线"),/*** 实体已被删除的标记*/DELETED(-1, "已删除");/*** * @param value* @param desc*/Status(Integer value, String desc) {this.value = value;this.desc = desc;}private Integer value;@Overridepublic Integer getValue() {return value;}private String desc;@Overridepublic String getDesc() {return desc;}@Overridepublic boolean isUsingOrdinal() {return false;}
}

枚举的类型

一般我们都是用 int 即可,但不排除用字符串的。是 int 还是 String 我们要让程序知道,于是派生两个接口 IntegerValueEnumStringValueEnum

/*** 枚举值是 int 的* * @author Frank Cheung<sp42@qq.com>*/
public interface IntegerValueEnum extends BaseEnmu {/*** 获取 POJO 字段的值* * @return*/public Integer getValue();/*** 说明是否使用自动的序号 value。* * 为了省事,不用给枚举赋值 1、2、3……,使用系统的索引。但是有个问题 ordinal 是 0 开始的,这里标记是 ordinal,那么反序列化的时候* +1。 当然如果你自己定义 value,那么就要把这个值设为 false* * @return*/default boolean isUsingOrdinal() {return true;}
}
/*** 枚举值是 String 的* * @author Frank Cheung<sp42@qq.com>*/
public interface StringValueEnum extends BaseEnmu {/*** 获取 POJO 字段的值* * @return*/String getValue();
}

Enum 的 ordinal() 能返回枚举在数组中的索引,这个允许我们无须定义枚举值,按照枚举出现的顺序就好了。但它是从零开始算的,——万一我常量没有 0,而是从 1 开始算的——那就对不上了。于是我们提供一个标识,说明使用了 ordinal() 机制。

/*** 说明是否使用自动的序号 value。* * 为了省事,不用给枚举赋值 1、2、3……,使用系统的索引。但是有个问题 ordinal 是 0 开始的,这里标记是 ordinal,那么反序列化的时候* +1。 当然如果你自己定义 value,那么就要把这个值设为 false* * @return*/
default boolean isUsingOrdinal() {return true;
}

默认是使用的。如果你自己定义 value,那么就要把这个值设为 false

枚举的转换

前面说到序列化与反序列化的问题,这里谈谈具体如何解决。首先说说 Json 输出的,很简单,就是遇到枚举读取其值即可。


如截图,在不同类型的转换中,判断是否 BaseEnum,然后转换即可,——一句两句代码的事情。如下图所示,是返回的 Json。


接着是,如何从数据库的值,转换到 Enum 呢?这个相对比较“烧脑”但其实也不难。笔者直接贴代码好了。

/*** 数据库中的值转换为 Java 枚举* * @param propertyType* @param _value* @return*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private static Object dbValue2Enum(Class<?> propertyType, Object _value) {if (_value != null) {boolean isNumber = _value instanceof Number, isString = _value instanceof String; // 写在这里不用在 for 里面每次判断for (Object e : propertyType.getEnumConstants()) {if (isNumber) {IntegerValueEnum _e = (IntegerValueEnum) e;Integer _int = ((Integer) _value) - (_e.isUsingOrdinal() ? 1 : 0);if (_int == _e.getValue()) {return e;}} else if (isString)return Enum.valueOf((Class<Enum>) propertyType, _value + "");}}return null;
}

这里笔者自研的 ORM 框架,在遍历数据库字段转换到 Java Bean 时候,调用 dbValue2Enum()


Java 反射很方便的提供了 isEnum()getEnumConstants() 使得可以让输入值与枚举值匹配上,——不然我真不知道该如何处理,使用注解说明哪个枚举类?太复杂了恐怕得不偿失。

小结

最后希望你会喜欢这套机制,或者给你带来一点启发。不足之处,敬请提出!

为实体提供枚举类型的支持相关推荐

  1. python枚举类型_Python 的枚举类型

    起步 Python 中的枚举类型 Python 的原生类型中并不包含枚举类型.为了提供更好的解决方案,Python 通过 PEP 435 在 3.4 版本中添加了 enum 标准库. 枚举类型可以看作 ...

  2. JVM:方法调用之动态类型语言支持。

    Java虚拟机的字节码指令集的数量从Sun公司的第一款Java虚拟机问世至JDK 7来临之前的十余年时间里,一致没有发生任何变化.随着JDK 7的发布,字节码指令集终于迎来了第一位新成员--invok ...

  3. java实体类中有枚举类型_实体类的枚举属性--原来支持枚举类型这么简单,没有EF5.0也可以...

    通常,我们都是在业务层和界面层使用枚举类型,这能够为我们编程带来便利,但在数据访问层,不使用枚举类型,因为很多数据库都不支持,比如我们现在用的SqlServer2008就不支持枚举类型的列,用的时候也 ...

  4. ef 在此上下文中只支持基本类型或枚举类型_Java 中的 6 颗语法糖

    作者:Java 技术栈来源:SegmentFault 思否社区 原文作者:danchu原文链接:https://blog.csdn.net/danchu/article/details/5498644 ...

  5. 【转】【翻译】实体框架中的POCO支持 - 第二部分 - 复杂类型,延迟装载和显式装载...

    [原文地址]POCO in the Entity Framework : Part 2 – Complex Types, Deferred Loading and Explicit Loading [ ...

  6. ef 在此上下文中只支持基本类型或枚举类型_Java枚举不应该成为你成功路上得绊脚石,源码给你讲解清楚

    现在在面试的过程中,基础得东西占的比重越来越高,尤其是对于Java底层得一些东西,比方说今天得内容---枚举,单纯说这些知识点其实并不难,甚至在日常得工作中用到的都不算多,但是,在面试的过程中会问到你 ...

  7. 扩展可以支持枚举类型的DorpDownList控件

         我们有很多时候,都会定义一些枚举类型的变量,而我们用的时候,也习惯用DropDownList绑定,绑定的方式也有好多种,比如集合,泛型集合等等.      比如:我们定义一个图片后缀名的枚举 ...

  8. 实体框架提供程序类型无法加载?

    本文翻译自:Entity Framework Provider type could not be loaded? I am trying to run my tests on TeamCity wh ...

  9. 用友uap nc65 如何实现一个下拉框(枚举类型实体)

    用友uap  nc65 如何实现一个下拉框(枚举类型实体) 如上图所示: 1.新建一个bmf文件. 2.建立一个枚举. 3.给枚举赋值.注意枚举值从0开始 4.右键发布元数据. 5.在需要引用的元数据 ...

最新文章

  1. 用UML做好系统分析
  2. 让PHP更快的提供文件下载 【转】
  3. mysql忽略大小写配置cnetos_CentOS7下安装MYSQL8.X并设置忽略大小写
  4. Java编程配置思路详解
  5. java序列化算法透析_Java序列化机制与原理的深入分析
  6. [云炬创业学笔记]第二章决定成为创业者测试3
  7. Python 数据增强 -- PIL模块
  8. Android 中SharedPreferences 使用
  9. vray学习笔记(3)-多维子材质是个什么东西
  10. 计算机组成第五章课后答案,计算机组成原理第五章答案
  11. 企业微信管理员可以看到打卡位置吗
  12. 关于二进制转换为十六进制
  13. python入门基础知识(九):函数
  14. 微信新功能,最牛的不是“斗图”!
  15. Spring - 解决 SpringUtil getBean NPE 问题
  16. 微信小程序 模仿华为音乐 列表界面
  17. 从零学习游戏服务器开发(一) 从一款多人联机实时对战游戏开始
  18. Ajax入门-搭建服务器并使用ajax技术向服务器发送一个请求并获得服务器返回的数据
  19. MySQL表字段类型
  20. 奥特曼系列ol以前的服务器恢复,奥特曼系列ol怎么看之前登录过的大区

热门文章

  1. 【云宏大讲坛】超融合,融合的不仅是基础架构
  2. 【科软课程-信息安全】Lab12 SQL Injection Attack
  3. 爬虫--可视化项目(一)
  4. 算法竞赛入门【码蹄集进阶塔335题】(MT2076-2100)
  5. 丁神去谷歌-北邮OJ416
  6. 【Python爬虫】Python+Selenium爬取百度圣卡/网易白金卡手机靓号
  7. golang的运维开发
  8. python一键批量制作word邀请函
  9. 怎么查看CAD图纸并更改图纸背景颜色?
  10. Linux下查看CPU、内存、磁盘使用情况,并计算其使用率