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.handler; 017 018import com.mybatisflex.annotation.EnumValue; 019import com.mybatisflex.core.exception.FlexExceptions; 020import com.mybatisflex.core.util.ClassUtil; 021import com.mybatisflex.core.util.StringUtil; 022import org.apache.ibatis.type.BaseTypeHandler; 023import org.apache.ibatis.type.JdbcType; 024 025import java.lang.reflect.Field; 026import java.lang.reflect.Method; 027import java.lang.reflect.Modifier; 028import java.sql.CallableStatement; 029import java.sql.PreparedStatement; 030import java.sql.ResultSet; 031import java.sql.SQLException; 032import java.util.List; 033 034public class FlexEnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> { 035 036 private Class<?> enumPropertyType; 037 private E[] enums; 038 private Field property; 039 private Method getter; 040 041 public FlexEnumTypeHandler(Class<E> enumClass) { 042 List<Field> allFields = ClassUtil.getAllFields(enumClass, field -> field.getAnnotation(EnumValue.class) != null); 043 Field field = allFields.get(0); 044 045 String fieldGetterName = "get" + StringUtil.firstCharToUpperCase(field.getName()); 046 List<Method> allMethods = ClassUtil.getAllMethods(enumClass, method -> { 047 String methodName = method.getName(); 048 return methodName.equals(fieldGetterName); 049 }); 050 051 enumPropertyType = ClassUtil.wrap(field.getType()); 052 enums = enumClass.getEnumConstants(); 053 054 if (allMethods.isEmpty()) { 055 if (Modifier.isPublic(field.getModifiers())) { 056 property = field; 057 } else { 058 throw new IllegalStateException("Can not find \"" + fieldGetterName + "()\" method in enum: " + enumClass.getName()); 059 } 060 } else { 061 getter = allMethods.get(0); 062 } 063 064 } 065 066 067 @Override 068 public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { 069 Object value = getValue(parameter); 070 if (jdbcType == null) { 071 ps.setObject(i, value); 072 } else { 073 ps.setObject(i, value, jdbcType.TYPE_CODE); 074 } 075 } 076 077 078 private Object getValue(E object) { 079 try { 080 return getter != null 081 ? getter.invoke(object) 082 : property.get(object); 083 } catch (Exception e) { 084 throw FlexExceptions.wrap(e); 085 } 086 } 087 088 089 @Override 090 public E getNullableResult(ResultSet rs, String columnName) throws SQLException { 091 Object value = rs.getObject(columnName, this.enumPropertyType); 092 if (null == value && rs.wasNull()) { 093 return null; 094 } 095 return convertToEnum(value); 096 } 097 098 099 @Override 100 public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 101 Object value = rs.getObject(columnIndex, this.enumPropertyType); 102 if (null == value && rs.wasNull()) { 103 return null; 104 } 105 return convertToEnum(value); 106 } 107 108 109 @Override 110 public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 111 Object value = cs.getObject(columnIndex, this.enumPropertyType); 112 if (null == value && cs.wasNull()) { 113 return null; 114 } 115 return convertToEnum(value); 116 } 117 118 119 private E convertToEnum(Object value) { 120 for (E e : enums) { 121 if (value.equals(getValue(e))) { 122 return e; 123 } 124 } 125 return null; 126 } 127 128}