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; 020import org.apache.ibatis.util.MapUtil; 021 022import java.lang.reflect.Field; 023import java.lang.reflect.Method; 024import java.lang.reflect.Modifier; 025import java.util.Map; 026import java.util.concurrent.ConcurrentHashMap; 027 028public class EnumWrapper<E extends Enum<E>> { 029 030 private static final Map<Class, EnumWrapper> cache = new ConcurrentHashMap<>(); 031 032 private boolean hasEnumValueAnnotation = false; 033 034 private Class<?> enumClass; 035 private E[] enums; 036 private Field property; 037 private Class<?> propertyType; 038 private Method getterMethod; 039 040 public static <R extends Enum<R>> EnumWrapper<R> of(Class<?> enumClass) { 041 return MapUtil.computeIfAbsent(cache, enumClass, EnumWrapper::new); 042 } 043 044 public EnumWrapper(Class<E> enumClass) { 045 this.enumClass = enumClass; 046 this.enums = enumClass.getEnumConstants(); 047 048 Field enumValueField = ClassUtil.getFirstField(enumClass, field -> field.getAnnotation(EnumValue.class) != null); 049 if (enumValueField != null) { 050 hasEnumValueAnnotation = true; 051 } 052 053 if (hasEnumValueAnnotation) { 054 String getterMethodName = "get" + StringUtil.firstCharToUpperCase(enumValueField.getName()); 055 056 Method getter = ClassUtil.getFirstMethod(enumClass, method -> { 057 String methodName = method.getName(); 058 return methodName.equals(getterMethodName) && Modifier.isPublic(method.getModifiers()); 059 }); 060 061 propertyType = ClassUtil.getWrapType(enumValueField.getType()); 062 063 if (getter == null) { 064 if (Modifier.isPublic(enumValueField.getModifiers())) { 065 property = enumValueField; 066 } else { 067 throw new IllegalStateException("Can not find method \"" + getterMethodName + "()\" in enum: " + enumClass.getName()); 068 } 069 } else { 070 this.getterMethod = getter; 071 } 072 } 073 } 074 075 076 public Object getEnumValue(E object) { 077 try { 078 return getterMethod != null ? getterMethod.invoke(object) : property.get(object); 079 } catch (Exception e) { 080 throw FlexExceptions.wrap(e); 081 } 082 } 083 084 085 public E getEnum(Object value) { 086 if (value != null) { 087 for (E e : enums) { 088 if (value.equals(getEnumValue(e))) { 089 return e; 090 } 091 } 092 } 093 return null; 094 } 095 096 097 public boolean hasEnumValueAnnotation() { 098 return hasEnumValueAnnotation; 099 } 100 101 public Class<?> getEnumClass() { 102 return enumClass; 103 } 104 105 public E[] getEnums() { 106 return enums; 107 } 108 109 public Field getProperty() { 110 return property; 111 } 112 113 public Class<?> getPropertyType() { 114 return propertyType; 115 } 116 117 public Method getGetterMethod() { 118 return getterMethod; 119 } 120 121}