001/* 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.util; 017 018import com.mybatisflex.annotation.EnumValue; 019import com.mybatisflex.core.exception.FlexExceptions; 020 021import java.lang.reflect.Field; 022import java.lang.reflect.Method; 023import java.lang.reflect.Modifier; 024import java.util.Map; 025import java.util.concurrent.ConcurrentHashMap; 026 027public class EnumWrapper<E extends Enum<E>> { 028 029 private static final Map<Class, EnumWrapper> cache = new ConcurrentHashMap<>(); 030 031 private boolean hasEnumValueAnnotation = false; 032 033 private Class<?> enumClass; 034 private E[] enums; 035 private Field property; 036 private Class<?> propertyType; 037 private Method getterMethod; 038 039 public static <R extends Enum<R>> EnumWrapper<R> of(Class<?> enumClass) { 040 return MapUtil.computeIfAbsent(cache, enumClass, EnumWrapper::new); 041 } 042 043 public EnumWrapper(Class<E> enumClass) { 044 this.enumClass = enumClass; 045 this.enums = enumClass.getEnumConstants(); 046 047 Field enumValueField = ClassUtil.getFirstField(enumClass, field -> field.getAnnotation(EnumValue.class) != null); 048 if (enumValueField != null) { 049 hasEnumValueAnnotation = true; 050 } 051 052 if (hasEnumValueAnnotation) { 053 String getterMethodName = "get" + StringUtil.firstCharToUpperCase(enumValueField.getName()); 054 055 Method getter = ClassUtil.getFirstMethod(enumClass, method -> { 056 String methodName = method.getName(); 057 return methodName.equals(getterMethodName) && Modifier.isPublic(method.getModifiers()); 058 }); 059 060 propertyType = ClassUtil.getWrapType(enumValueField.getType()); 061 062 if (getter == null) { 063 if (Modifier.isPublic(enumValueField.getModifiers())) { 064 property = enumValueField; 065 } else { 066 throw new IllegalStateException("Can not find method \"" + getterMethodName + "()\" in enum: " + enumClass.getName()); 067 } 068 } else { 069 this.getterMethod = getter; 070 } 071 } 072 073 if (!hasEnumValueAnnotation) { 074 Method enumValueMethod = ClassUtil.getFirstMethod(enumClass, method -> method.getAnnotation(EnumValue.class) != null); 075 if (enumValueMethod != null) { 076 String methodName = enumValueMethod.getName(); 077 if (!(methodName.startsWith("get") && methodName.length() > 3)) { 078 throw new IllegalStateException("Can not find get method \"" + methodName + "()\" in enum: " + enumClass.getName()); 079 } 080 this.getterMethod = enumValueMethod; 081 this.hasEnumValueAnnotation = true; 082 Class<?> returnType = enumValueMethod.getReturnType(); 083 if (returnType.isPrimitive()) { 084 returnType = ConvertUtil.primitiveToBoxed(returnType); 085 } 086 this.propertyType = returnType; 087 } 088 } 089 } 090 091 /** 092 * 获取枚举值 093 * 顺序: 094 * 1、@EnumValue标识的get方法 095 * 2、@EnumValue标识的属性 096 * 3、没有使用@EnumValue,取枚举name 097 * 098 * @param object 099 * @return 100 */ 101 public Object getEnumValue(E object) { 102 try { 103 if (getterMethod != null) { 104 return getterMethod.invoke(object); 105 } else if(property != null){ 106 return property.get(object); 107 } else { 108 return object.name(); 109 } 110 } catch (Exception e) { 111 throw FlexExceptions.wrap(e); 112 } 113 } 114 115 116 public E getEnum(Object value) { 117 if (value != null) { 118 for (E e : enums) { 119 if (value.equals(getEnumValue(e))) { 120 return e; 121 } 122 } 123 } 124 return null; 125 } 126 127 128 public boolean hasEnumValueAnnotation() { 129 return hasEnumValueAnnotation; 130 } 131 132 public Class<?> getEnumClass() { 133 return enumClass; 134 } 135 136 public E[] getEnums() { 137 return enums; 138 } 139 140 public Field getProperty() { 141 return property; 142 } 143 144 public Class<?> getPropertyType() { 145 return propertyType; 146 } 147 148 public Method getGetterMethod() { 149 return getterMethod; 150 } 151 152}