java 使用 morphia 存取枚举为值
2019-12-31 16:04:34来源:博客园 阅读 ()
java 使用 morphia 存取枚举为值
前言
morphia是java 使用orm方式操作mongodb的一个库。但是默认情况下,使用morphia存取enum时,是按名字存取的。而我们需要把enum按照值存取。
如图:schoolClassLevel1字段是默认的按enum的name进行存取的,schoolClassLevel是我们想要的(按值存取)。
核心代码
初始化 morphia
Morphia morphia = new Morphia(); try { Converters converters = morphia.getMapper().getConverters(); Method getEncoder = Converters.class.getDeclaredMethod("getEncoder", Class.class); getEncoder.setAccessible(true); TypeConverter enco = ((TypeConverter) getEncoder.invoke(converters, SchoolClassLevel.class)); converters.removeConverter(enco); converters.addConverter(new EnumOrginalConverter()); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }
其中, EnumOrginalConverter.java
package zhongcy.demos.converter; import dev.morphia.converters.SimpleValueConverter; import dev.morphia.converters.TypeConverter; import zhongcy.demos.util.EnumOriginalProvider; import zhongcy.demos.util.EnumUtil; public class EnumOrginalConverter extends TypeConverter implements SimpleValueConverter { @Override @SuppressWarnings({"unchecked", "deprecation"}) public Object decode(final Class targetClass, final Object fromDBObject, final dev.morphia.mapping.MappedField optionalExtraInfo) { if (fromDBObject == null) { return null; } if (hasEnumOriginalProvider(targetClass)) { return EnumUtil.getEnumObject(Long.parseLong(fromDBObject.toString()), targetClass); } return Enum.valueOf(targetClass, fromDBObject.toString()); } @Override @SuppressWarnings({"unchecked", "deprecation"}) public Object encode(final Object value, final dev.morphia.mapping.MappedField optionalExtraInfo) { if (value == null) { return null; } if (hasEnumOriginalProvider(value.getClass())) { return ((EnumOriginalProvider) value).getIdx(); } return getName(((Enum) value)); } private boolean hasEnumOriginalProvider(Class clzz) { Class<?>[] interfaces = clzz.getInterfaces(); if (interfaces.length < 1) { return false; } if (interfaces.length == 1) { return interfaces[0] == EnumOriginalProvider.class; } else { for (Class<?> it : interfaces) { if (it == EnumOriginalProvider.class) { return true; } } return false; }
} @Override @SuppressWarnings({"unchecked", "deprecation"}) protected boolean isSupported(final Class c, final dev.morphia.mapping.MappedField optionalExtraInfo) { return c.isEnum(); } private <T extends Enum> String getName(final T value) { return value.name(); } }
EnumOriginalProvider.java
package zhongcy.demos.util; /** * enum 的原始数据提供 */ public interface EnumOriginalProvider { default String getName() { return null; } long getIdx(); }
EnumUtil.java
package zhongcy.demos.util; import org.apache.calcite.linq4j.Linq4j; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class EnumUtil { private static EnumUtil instance = new EnumUtil(); Impl impl; EnumUtil() { impl = new Impl(); } /** * * 获取value返回枚举对象 * * @param value name 或 index * * @param clazz 枚举类型 * * */ public static <T extends EnumOriginalProvider> T getEnumObject(long idx, Class<T> clazz) { return instance.impl.getEnumObject(idx, clazz); } public static <T extends EnumOriginalProvider> T getEnumObject(String name, Class<T> clazz) { return instance.impl.getEnumObject(name, clazz); } private class Impl { private Map<Class, EnumFeature[]> enumMap; public Impl() { enumMap = new HashMap<>(); } public <T extends EnumOriginalProvider> T getEnumObject(long value, Class<T> clazz) { if (!enumMap.containsKey(clazz)) { enumMap.put(clazz, createEnumFeatures(clazz)); } try { EnumFeature first = Linq4j.asEnumerable(enumMap.get(clazz)) .firstOrDefault(f -> value == f.getIndex()); if (first != null) { return (T) first.getEnumValue(); } } catch (Exception e) { } return null; } public <T extends EnumOriginalProvider> T getEnumObject(String value, Class<T> clazz) { if (!enumMap.containsKey(clazz)) { enumMap.put(clazz, createEnumFeatures(clazz)); } try { EnumFeature first = Linq4j.asEnumerable(enumMap.get(clazz)) .firstOrDefault(f -> value.equals(f.getName()) || f.getEnumValue().toString().equals(value)); if (first != null) { return (T) first.getEnumValue(); } } catch (Exception e) { } return null; } @SuppressWarnings("JavaReflectionInvocation") private <T extends EnumOriginalProvider> EnumFeature[] createEnumFeatures(Class<T> cls) { Method method = null; try { method = cls.getMethod("values"); return Linq4j.asEnumerable((EnumOriginalProvider[]) method.invoke(null, (Object[]) null)) .select(s -> new EnumFeature(s, s.getName(), s.getIdx())).toList().toArray(new EnumFeature[0]); } catch (Exception e) { e.printStackTrace(); return new EnumFeature[0]; } } } private class EnumFeature { Object enumValue; String name; long index; public EnumFeature(Object enumValue, String name, long index) { this.enumValue = enumValue; this.name = name; this.index = index; } public Object getEnumValue() { return enumValue; } public String getName() { return name; } public long getIndex() { return index; } } }
morphia简单分析
通过 dev.morphia.DataStoreImpl 的save方法,一路跟踪
到这一步后,查看 TypeConverter 的实现,
找到 EnumConverter,可以看到,morphia 在编码 enum 时,使用的是 enum.getname,我们就想办法替换这个converter.
package dev.morphia.converters; import dev.morphia.mapping.MappedField; /** * @author Uwe Schaefer, (us@thomas-daily.de) * @author scotthernandez */ public class EnumConverter extends TypeConverter implements SimpleValueConverter { @Override @SuppressWarnings("unchecked") public Object decode(final Class targetClass, final Object fromDBObject, final MappedField optionalExtraInfo) { if (fromDBObject == null) { return null; } return Enum.valueOf(targetClass, fromDBObject.toString()); } @Override public Object encode(final Object value, final MappedField optionalExtraInfo) { if (value == null) { return null; } return getName((Enum) value); } @Override protected boolean isSupported(final Class c, final MappedField optionalExtraInfo) { return c.isEnum(); } private <T extends Enum> String getName(final T value) { return value.name(); } }View Code
Converter替换
查看morphia 的接口,获取 Converters 的方法如下
Converters converters = morphia.getMapper().getConverters();
但是,Converters的接口里面,相关的方法都不是 public..
查看 Converters 的初始化,也发现,初始化路径很长,也不提供设置一个自定义的Converters子类。所以,采取了反射方法,找到enumConvert, 替换成支持返回值得Converter。
即:
Converters converters = morphia.getMapper().getConverters(); Method getEncoder = Converters.class.getDeclaredMethod("getEncoder", Class.class); getEncoder.setAccessible(true); TypeConverter enco = ((TypeConverter) getEncoder.invoke(converters, SchoolClassLevel.class)); converters.removeConverter(enco); converters.addConverter(new EnumOrginalConverter());View Code
EnumOrginalConverter的实现
实现就比较简单了,通过判断enum是否有指定的 interface(EnumOriginalProvider),如果有,encode 方法就返回值。
代码见上面(EnumOrginalConverter)
源码定义了两个枚举:
最终数据库 SchoolClassLevel为值,SchoolClassLevel1为name
源码
https://github.com/zhongchengyi/zhongcy.demos/tree/master/mongo-morphia-demo
其他
- morphia: https://github.com/MorphiaOrg/morphia
- 快速入门:https://www.jianshu.com/p/fb8f0b46a03a
原文链接:https://www.cnblogs.com/zhongchengyi/p/12125014.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- 国外程序员整理的Java资源大全(全部是干货) 2020-06-12
- 2020年深圳中国平安各部门Java中级面试真题合集(附答案) 2020-06-11
- 2020年java就业前景 2020-06-11
- 04.Java基础语法 2020-06-11
- Java--反射(框架设计的灵魂)案例 2020-06-11
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash