DefaultObjectFactory.java

  1. /*
  2.  *    Copyright 2009-2024 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.factory;

  17. import java.io.Serializable;
  18. import java.lang.reflect.Constructor;
  19. import java.util.ArrayList;
  20. import java.util.Collection;
  21. import java.util.Collections;
  22. import java.util.HashMap;
  23. import java.util.HashSet;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.Optional;
  27. import java.util.Set;
  28. import java.util.SortedSet;
  29. import java.util.TreeSet;
  30. import java.util.stream.Collectors;

  31. import org.apache.ibatis.reflection.ReflectionException;
  32. import org.apache.ibatis.reflection.Reflector;

  33. /**
  34.  * @author Clinton Begin
  35.  */
  36. public class DefaultObjectFactory implements ObjectFactory, Serializable {

  37.   private static final long serialVersionUID = -8855120656740914948L;

  38.   @Override
  39.   public <T> T create(Class<T> type) {
  40.     return create(type, null, null);
  41.   }

  42.   @SuppressWarnings("unchecked")
  43.   @Override
  44.   public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
  45.     Class<?> classToCreate = resolveInterface(type);
  46.     // we know types are assignable
  47.     return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
  48.   }

  49.   private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
  50.     try {
  51.       Constructor<T> constructor;
  52.       if (constructorArgTypes == null || constructorArgs == null) {
  53.         constructor = type.getDeclaredConstructor();
  54.         try {
  55.           return constructor.newInstance();
  56.         } catch (IllegalAccessException e) {
  57.           if (Reflector.canControlMemberAccessible()) {
  58.             constructor.setAccessible(true);
  59.             return constructor.newInstance();
  60.           }
  61.           throw e;
  62.         }
  63.       }
  64.       constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));
  65.       try {
  66.         return constructor.newInstance(constructorArgs.toArray(new Object[0]));
  67.       } catch (IllegalAccessException e) {
  68.         if (Reflector.canControlMemberAccessible()) {
  69.           constructor.setAccessible(true);
  70.           return constructor.newInstance(constructorArgs.toArray(new Object[0]));
  71.         }
  72.         throw e;
  73.       }
  74.     } catch (Exception e) {
  75.       String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList).stream()
  76.           .map(Class::getSimpleName).collect(Collectors.joining(","));
  77.       String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList).stream()
  78.           .map(String::valueOf).collect(Collectors.joining(","));
  79.       throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values ("
  80.           + argValues + "). Cause: " + e, e);
  81.     }
  82.   }

  83.   protected Class<?> resolveInterface(Class<?> type) {
  84.     Class<?> classToCreate;
  85.     if (type == List.class || type == Collection.class || type == Iterable.class) {
  86.       classToCreate = ArrayList.class;
  87.     } else if (type == Map.class) {
  88.       classToCreate = HashMap.class;
  89.     } else if (type == SortedSet.class) { // issue #510 Collections Support
  90.       classToCreate = TreeSet.class;
  91.     } else if (type == Set.class) {
  92.       classToCreate = HashSet.class;
  93.     } else {
  94.       classToCreate = type;
  95.     }
  96.     return classToCreate;
  97.   }

  98.   @Override
  99.   public <T> boolean isCollection(Class<T> type) {
  100.     return Collection.class.isAssignableFrom(type);
  101.   }

  102. }