001/* 002 * Copyright (c) 2022-2025, 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 final Class<?> enumClass; 034 private final 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.getFirstMethodByAnnotation(enumClass, EnumValue.class); 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 081 String enumValueFieldName; 082 if (methodName.startsWith("get")) { 083 enumValueFieldName = StringUtil.firstCharToLowerCase(enumValueMethod.getName().substring(3)); 084 } else { 085 enumValueFieldName = enumValueMethod.getName().toLowerCase(); 086 } 087 enumValueField = ClassUtil.getFirstField(enumClass, field -> enumValueFieldName.equals(field.getName())); 088 if (enumValueField != null) { 089 propertyType = ClassUtil.getWrapType(enumValueField.getType()); 090 } else { 091 throw new IllegalStateException("Can not find field \"" + enumValueFieldName + "()\" in enum: " + enumClass.getName()); 092 } 093 094 this.getterMethod = enumValueMethod; 095 this.hasEnumValueAnnotation = true; 096 } 097 } 098 } 099 100 /** 101 * 获取枚举值 102 * 顺序: 103 * 1、@EnumValue标识的get方法 104 * 2、@EnumValue标识的属性 105 * 3、没有使用@EnumValue,取枚举name 106 * 107 * @param object 108 * @return 109 */ 110 public Object getEnumValue(Object object) { 111 try { 112 if (getterMethod != null) { 113 return getterMethod.invoke(object); 114 } else if (property != null) { 115 return property.get(object); 116 } else { 117 //noinspection unchecked 118 return ((E) object).name(); 119 } 120 } catch (Exception e) { 121 throw FlexExceptions.wrap(e); 122 } 123 } 124 125 126 public E getEnum(Object value) { 127 if (value != null) { 128 for (E e : enums) { 129 if (value.equals(getEnumValue(e))) { 130 return e; 131 } 132 } 133 } 134 return null; 135 } 136 137 138 public boolean hasEnumValueAnnotation() { 139 return hasEnumValueAnnotation; 140 } 141 142 public Class<?> getEnumClass() { 143 return enumClass; 144 } 145 146 public E[] getEnums() { 147 return enums; 148 } 149 150 public Field getProperty() { 151 return property; 152 } 153 154 public Class<?> getPropertyType() { 155 return propertyType; 156 } 157 158 public Method getGetterMethod() { 159 return getterMethod; 160 } 161 162}