package  com. test. common. orm. builder ; import  cn. hutool. core. util.  IdUtil ; 
import  com. baomidou. mybatisplus. core. conditions. query.  QueryWrapper ; 
import  org. apache. ibatis. cache.  Cache ; 
import  org. apache. ibatis. cache. impl.  PerpetualCache ; 
import  org. springframework. util.  Assert ; 
import  org. springframework. util.  ReflectionUtils ; 
import  org. springframework. util.  StringUtils ; import  java. lang. annotation.  * ; 
import  java. lang. reflect.  Field ; 
import  java. lang. reflect.  Method ; 
import  java. util.  * ; 
import  java. util. concurrent. atomic.  AtomicInteger ; 
import  java. util. stream.  Stream ; public  final  class  QueryWrapperBuilder  { private  static  final  Cache  FILED_CACHE  =  new  PerpetualCache ( IdUtil . simpleUUID ( ) ) ; private  static  final  Cache  METHOD_CACHE  =  new  PerpetualCache ( IdUtil . simpleUUID ( ) ) ; private  static  final  char [ ]  UPPER_CASE_CHAR_ARRAY  =  new  char [ 26 ] ; static  { UPPER_CASE_CHAR_ARRAY [ 0 ] = 'A' ; UPPER_CASE_CHAR_ARRAY [ 1 ] = 'B' ; UPPER_CASE_CHAR_ARRAY [ 2 ] = 'C' ; UPPER_CASE_CHAR_ARRAY [ 3 ] = 'D' ; UPPER_CASE_CHAR_ARRAY [ 4 ] = 'E' ; UPPER_CASE_CHAR_ARRAY [ 5 ] = 'F' ; UPPER_CASE_CHAR_ARRAY [ 6 ] = 'G' ; UPPER_CASE_CHAR_ARRAY [ 7 ] = 'H' ; UPPER_CASE_CHAR_ARRAY [ 8 ] = 'I' ; UPPER_CASE_CHAR_ARRAY [ 9 ] = 'J' ; UPPER_CASE_CHAR_ARRAY [ 10 ] = 'K' ; UPPER_CASE_CHAR_ARRAY [ 11 ] = 'L' ; UPPER_CASE_CHAR_ARRAY [ 12 ] = 'M' ; UPPER_CASE_CHAR_ARRAY [ 13 ] = 'N' ; UPPER_CASE_CHAR_ARRAY [ 14 ] = 'O' ; UPPER_CASE_CHAR_ARRAY [ 15 ] = 'P' ; UPPER_CASE_CHAR_ARRAY [ 16 ] = 'Q' ; UPPER_CASE_CHAR_ARRAY [ 17 ] = 'R' ; UPPER_CASE_CHAR_ARRAY [ 18 ] = 'S' ; UPPER_CASE_CHAR_ARRAY [ 19 ] = 'T' ; UPPER_CASE_CHAR_ARRAY [ 20 ] = 'U' ; UPPER_CASE_CHAR_ARRAY [ 21 ] = 'V' ; UPPER_CASE_CHAR_ARRAY [ 22 ] = 'W' ; UPPER_CASE_CHAR_ARRAY [ 23 ] = 'X' ; UPPER_CASE_CHAR_ARRAY [ 24 ] = 'Y' ; UPPER_CASE_CHAR_ARRAY [ 25 ] = 'Z' ; } public  static  < T > QueryWrapper < T > buildListWrapper ( final  Class < T > ,  final  Object  voObject,  Integer . . .  group)  { Assert . isTrue ( null  !=  entityClass, "entityClass cannot be null" ) ; Assert . isTrue ( null  !=  voObject, "voObject cannot be null" ) ; if ( group !=  null  &&  group. length >  1 )  { throw  new  IllegalArgumentException ( "group cannot greater than one" ) ; } AtomicInteger  defaultGroup =  new  AtomicInteger ( - 1 ) ; if ( null  ==  group ||  group. length <=  0 )  { defaultGroup. set ( 1 ) ; }  else  { defaultGroup. set ( group[ 0 ] ) ; } QueryWrapper < T > =  new  QueryWrapper < > ( ) ; Class < ? > =  voObject. getClass ( ) ; String  voClassName =  voObjectClass. getName ( ) ; Field [ ]  fields =  ( Field [ ] )  FILED_CACHE . getObject ( voClassName) ; if ( null  ==  fields)  { fields =  voObjectClass. getDeclaredFields ( ) ; if ( fields. length >  0 )  { FILED_CACHE . putObject ( voClassName,  fields) ; }  else  { throw  new  IllegalArgumentException ( "voObject ["  +  voClassName +  "] not has fields" ) ; } } Stream < Field > =  Arrays . stream ( fields) ; stream. forEach ( field ->  { if ( field. isAnnotationPresent ( QueryOperation . class )  ||  field. isAnnotationPresent ( QueryOperations . class ) )  { String  fieldName =  field. getName ( ) ; String  columnName =  fieldToColumnName ( fieldName) ; Annotation [ ]  annotations =  field. getAnnotations ( ) ; List < QueryOperation > =  new  ArrayList < > ( ) ; for ( Annotation  annotation :  annotations)  { if ( annotation instanceof  QueryOperations )  { QueryOperation [ ]  queryOperations =  ( ( QueryOperations )  annotation) . value ( ) ; list. addAll ( Arrays . asList ( queryOperations) ) ; }  else  if ( annotation instanceof  QueryOperation ) { list. add ( ( QueryOperation )  annotation) ; } } QueryOperation  queryOperation = list. stream ( ) . filter ( annotation -> annotation. group ( )  ==  defaultGroup. get ( ) ) . findFirst ( ) . orElse ( null ) ; if ( null  !=  queryOperation)  { String  annoColumnName =  queryOperation. columnName ( ) ; if ( StringUtils . hasText ( annoColumnName) )  { columnName =  annoColumnName; } QueryOperationType  queryOperationType =  queryOperation. value ( ) ; String  methodName =  fileNameToMethodName ( fieldName, "get" ) ; String  key =  voClassName +  "@"  +  methodName; Method  method =  ( Method )  METHOD_CACHE . getObject ( key) ; if ( null  ==  method)  { method =  ReflectionUtils . findMethod ( voObjectClass,  methodName) ; METHOD_CACHE . putObject ( key, method) ; } Assert . notNull ( method, "method : [ "  +  methodName +  " ] not exists in class : [ "  +  voObjectClass. getName ( )  +  "]" ) ; Object  o =  ReflectionUtils . invokeMethod ( method,  voObject) ; setQueryWrapper ( queryWrapper, queryOperationType, columnName, o) ; } } } ) ; return  queryWrapper; } public  static  String  fieldToColumnName ( String  fieldName)  { Assert . isTrue ( StringUtils . hasText ( fieldName) ,  "fieldName must contains at least one character" ) ; char [ ]  chars =  fieldName. toCharArray ( ) ; List < Integer > =  new  ArrayList < > ( ) ; for ( int  i= 0 ; i< chars. length; i++ )  { char  val =  chars[ i] ; for ( char  charVal :  UPPER_CASE_CHAR_ARRAY )  { if ( val ==  charVal)  { indexList. add ( i) ; break ; } } } fieldName =  fieldName. toLowerCase ( Locale . ENGLISH ) ; StringBuilder  columnName =  new  StringBuilder ( fieldName) ; indexList. forEach ( index-> { columnName. insert ( index, "_" ) ; } ) ; return  columnName. toString ( ) ; } public  static  String  fileNameToMethodName ( final  String  fieldName, String  prefix)  { return  prefix +  fieldName. substring ( 0 , 1 ) . toUpperCase ( Locale . ENGLISH )  +  fieldName. substring ( 1 ) ; } private  static  void  setQueryWrapper ( QueryWrapper < ? > ,  QueryOperationType  queryOperationType, String  columnName,  Object  o)  { boolean  canSet =  false ; if ( o instanceof  String )  { canSet =  StringUtils . hasLength ( ( CharSequence ) o)  ; }  else  { canSet =  null  !=  o ; } if ( canSet)  { if ( queryOperationType ==  QueryOperationType . EQUAL )  { queryWrapper. eq ( columnName, o) ; }  else  if ( queryOperationType ==  QueryOperationType . NOT_EQUAL )  { queryWrapper. ne ( columnName, o) ; }  else  if ( queryOperationType ==  QueryOperationType . LIKE )  { queryWrapper. like ( columnName, o) ; }  else  if ( queryOperationType ==  QueryOperationType . BETWEEN )  { if ( ! ( o instanceof  Collection < ? > ) )  { throw  new  UnsupportedOperationException ( "只对集合支持between操作" ) ; } if ( ( ( Collection < ? > )  o) . size ( )  <  2 )  { throw  new  IllegalArgumentException ( "集合中元素的数量异常" ) ; } Object [ ]  objArr =  ( ( Collection < ? > )  o) . toArray ( ) ; queryWrapper. between ( columnName,  objArr[ 0 ] ,  objArr[ 1 ] ) ; }  else  if ( queryOperationType ==  QueryOperationType . ORDER_ASC )  { queryWrapper. orderByAsc ( columnName) ; }  else  if ( queryOperationType ==  QueryOperationType . ORDER_DESC )  { queryWrapper. orderByDesc ( columnName) ; } } } @Target ( ElementType . FIELD ) @Retention ( RetentionPolicy . RUNTIME ) @Repeatable ( QueryOperations . class ) public  @interface  QueryOperation  { QueryOperationType  value ( )  default  QueryOperationType . EQUAL ; int  group ( )  default  1 ; String  columnName ( )  default  "" ; } @Target ( ElementType . FIELD ) @Retention ( RetentionPolicy . RUNTIME ) public  @interface  QueryOperations  { QueryOperation [ ]  value ( ) ; } public  enum  QueryOperationType  { EQUAL ( "equal" ) , NOT_EQUAL ( "not_equal" ) , LIKE ( "like" ) , BETWEEN ( "between" ) , ORDER_DESC ( "order_desc" ) , ORDER_ASC ( "order_asc" ) ; private  final  String  operationType; QueryOperationType ( String  operationType)  { this . operationType =  operationType; } } }