View Javadoc
1   /*
2    *    Copyright 2009-2021 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    *       http://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.submitted.custom_collection_handling;
17  
18  import java.lang.reflect.Array;
19  import java.lang.reflect.Constructor;
20  import java.util.Collection;
21  import java.util.HashSet;
22  import java.util.LinkedHashMap;
23  import java.util.LinkedList;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  import java.util.SortedSet;
28  import java.util.TreeSet;
29  
30  import org.apache.ibatis.reflection.ReflectionException;
31  import org.apache.ibatis.reflection.factory.ObjectFactory;
32  
33  public class CustomObjectFactory implements ObjectFactory {
34  
35      @Override
36      public <T> T create(Class<T> type) {
37          return create(type, null, null);
38      }
39  
40      @Override
41      public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
42          Class<?> classToCreate = resolveInterface(type);
43          @SuppressWarnings("unchecked") // we know types are assignable
44          T created = (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
45          return created;
46      }
47  
48      private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
49          try {
50              Constructor<T> constructor;
51              if (constructorArgTypes == null || constructorArgs == null) {
52                  constructor = type.getDeclaredConstructor();
53                  if (!constructor.isAccessible()) {
54                      constructor.setAccessible(true);
55                  }
56                  return constructor.newInstance();
57              }
58              constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
59              if (!constructor.isAccessible()) {
60                  constructor.setAccessible(true);
61              }
62              return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
63          } catch (Exception e) {
64              StringBuilder argTypes = new StringBuilder();
65              if (constructorArgTypes != null) {
66                  for (Class<?> argType : constructorArgTypes) {
67                      argTypes.append(argType.getSimpleName());
68                      argTypes.append(",");
69                  }
70              }
71              StringBuilder argValues = new StringBuilder();
72              if (constructorArgs != null) {
73                  for (Object argValue : constructorArgs) {
74                      argValues.append(String.valueOf(argValue));
75                      argValues.append(",");
76                  }
77              }
78              throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
79          }
80      }
81  
82      private Class<?> resolveInterface(Class<?> type) {
83          Class<?> classToCreate;
84          if (type == List.class || type == Collection.class) {
85              classToCreate = LinkedList.class;
86          } else if (type == Map.class) {
87              classToCreate = LinkedHashMap.class;
88          } else if (type == SortedSet.class) { // issue #510 Collections Support
89              classToCreate = TreeSet.class;
90          } else if (type == Set.class) {
91              classToCreate = HashSet.class;
92          } else {
93              classToCreate = type;
94          }
95          return classToCreate;
96      }
97  
98      @Override
99      public <T> boolean isCollection(Class<T> type) {
100       return CustomCollection.class.isAssignableFrom(type);
101     }
102 
103     @SuppressWarnings("unchecked")
104     public <T> T[] createArray(Class<T> type, int size) {
105       return (T[]) Array.newInstance(type, size);
106     }
107 
108 }