MetaClass.java

  1. /*
  2.  *    Copyright 2009-2023 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       https://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package org.apache.ibatis.reflection;

  17. import java.lang.reflect.Field;
  18. import java.lang.reflect.Method;
  19. import java.lang.reflect.ParameterizedType;
  20. import java.lang.reflect.Type;
  21. import java.util.Collection;

  22. import org.apache.ibatis.reflection.invoker.GetFieldInvoker;
  23. import org.apache.ibatis.reflection.invoker.Invoker;
  24. import org.apache.ibatis.reflection.invoker.MethodInvoker;
  25. import org.apache.ibatis.reflection.property.PropertyTokenizer;

  26. /**
  27.  * @author Clinton Begin
  28.  */
  29. public class MetaClass {

  30.   private final ReflectorFactory reflectorFactory;
  31.   private final Reflector reflector;

  32.   private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
  33.     this.reflectorFactory = reflectorFactory;
  34.     this.reflector = reflectorFactory.findForClass(type);
  35.   }

  36.   public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
  37.     return new MetaClass(type, reflectorFactory);
  38.   }

  39.   public MetaClass metaClassForProperty(String name) {
  40.     Class<?> propType = reflector.getGetterType(name);
  41.     return MetaClass.forClass(propType, reflectorFactory);
  42.   }

  43.   public String findProperty(String name) {
  44.     StringBuilder prop = buildProperty(name, new StringBuilder());
  45.     return prop.length() > 0 ? prop.toString() : null;
  46.   }

  47.   public String findProperty(String name, boolean useCamelCaseMapping) {
  48.     if (useCamelCaseMapping) {
  49.       name = name.replace("_", "");
  50.     }
  51.     return findProperty(name);
  52.   }

  53.   public String[] getGetterNames() {
  54.     return reflector.getGetablePropertyNames();
  55.   }

  56.   public String[] getSetterNames() {
  57.     return reflector.getSetablePropertyNames();
  58.   }

  59.   public Class<?> getSetterType(String name) {
  60.     PropertyTokenizer prop = new PropertyTokenizer(name);
  61.     if (prop.hasNext()) {
  62.       MetaClass metaProp = metaClassForProperty(prop.getName());
  63.       return metaProp.getSetterType(prop.getChildren());
  64.     }
  65.     return reflector.getSetterType(prop.getName());
  66.   }

  67.   public Class<?> getGetterType(String name) {
  68.     PropertyTokenizer prop = new PropertyTokenizer(name);
  69.     if (prop.hasNext()) {
  70.       MetaClass metaProp = metaClassForProperty(prop);
  71.       return metaProp.getGetterType(prop.getChildren());
  72.     }
  73.     // issue #506. Resolve the type inside a Collection Object
  74.     return getGetterType(prop);
  75.   }

  76.   private MetaClass metaClassForProperty(PropertyTokenizer prop) {
  77.     Class<?> propType = getGetterType(prop);
  78.     return MetaClass.forClass(propType, reflectorFactory);
  79.   }

  80.   private Class<?> getGetterType(PropertyTokenizer prop) {
  81.     Class<?> type = reflector.getGetterType(prop.getName());
  82.     if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
  83.       Type returnType = getGenericGetterType(prop.getName());
  84.       if (returnType instanceof ParameterizedType) {
  85.         Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
  86.         if (actualTypeArguments != null && actualTypeArguments.length == 1) {
  87.           returnType = actualTypeArguments[0];
  88.           if (returnType instanceof Class) {
  89.             type = (Class<?>) returnType;
  90.           } else if (returnType instanceof ParameterizedType) {
  91.             type = (Class<?>) ((ParameterizedType) returnType).getRawType();
  92.           }
  93.         }
  94.       }
  95.     }
  96.     return type;
  97.   }

  98.   private Type getGenericGetterType(String propertyName) {
  99.     try {
  100.       Invoker invoker = reflector.getGetInvoker(propertyName);
  101.       if (invoker instanceof MethodInvoker) {
  102.         Field declaredMethod = MethodInvoker.class.getDeclaredField("method");
  103.         declaredMethod.setAccessible(true);
  104.         Method method = (Method) declaredMethod.get(invoker);
  105.         return TypeParameterResolver.resolveReturnType(method, reflector.getType());
  106.       }
  107.       if (invoker instanceof GetFieldInvoker) {
  108.         Field declaredField = GetFieldInvoker.class.getDeclaredField("field");
  109.         declaredField.setAccessible(true);
  110.         Field field = (Field) declaredField.get(invoker);
  111.         return TypeParameterResolver.resolveFieldType(field, reflector.getType());
  112.       }
  113.     } catch (NoSuchFieldException | IllegalAccessException e) {
  114.       // Ignored
  115.     }
  116.     return null;
  117.   }

  118.   public boolean hasSetter(String name) {
  119.     PropertyTokenizer prop = new PropertyTokenizer(name);
  120.     if (!prop.hasNext()) {
  121.       return reflector.hasSetter(prop.getName());
  122.     }
  123.     if (reflector.hasSetter(prop.getName())) {
  124.       MetaClass metaProp = metaClassForProperty(prop.getName());
  125.       return metaProp.hasSetter(prop.getChildren());
  126.     }
  127.     return false;
  128.   }

  129.   public boolean hasGetter(String name) {
  130.     PropertyTokenizer prop = new PropertyTokenizer(name);
  131.     if (!prop.hasNext()) {
  132.       return reflector.hasGetter(prop.getName());
  133.     }
  134.     if (reflector.hasGetter(prop.getName())) {
  135.       MetaClass metaProp = metaClassForProperty(prop);
  136.       return metaProp.hasGetter(prop.getChildren());
  137.     }
  138.     return false;
  139.   }

  140.   public Invoker getGetInvoker(String name) {
  141.     return reflector.getGetInvoker(name);
  142.   }

  143.   public Invoker getSetInvoker(String name) {
  144.     return reflector.getSetInvoker(name);
  145.   }

  146.   private StringBuilder buildProperty(String name, StringBuilder builder) {
  147.     PropertyTokenizer prop = new PropertyTokenizer(name);
  148.     if (prop.hasNext()) {
  149.       String propertyName = reflector.findPropertyName(prop.getName());
  150.       if (propertyName != null) {
  151.         builder.append(propertyName);
  152.         builder.append(".");
  153.         MetaClass metaProp = metaClassForProperty(propertyName);
  154.         metaProp.buildProperty(prop.getChildren(), builder);
  155.       }
  156.     } else {
  157.       String propertyName = reflector.findPropertyName(name);
  158.       if (propertyName != null) {
  159.         builder.append(propertyName);
  160.       }
  161.     }
  162.     return builder;
  163.   }

  164.   public boolean hasDefaultConstructor() {
  165.     return reflector.hasDefaultConstructor();
  166.   }

  167. }