View Javadoc
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.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      return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
44    }
45  
46    private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
47      try {
48        Constructor<T> constructor;
49        if (constructorArgTypes == null || constructorArgs == null) {
50          constructor = type.getDeclaredConstructor();
51          if (!constructor.isAccessible()) {
52            constructor.setAccessible(true);
53          }
54          return constructor.newInstance();
55        }
56        constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
57        if (!constructor.isAccessible()) {
58          constructor.setAccessible(true);
59        }
60        return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
61      } catch (Exception e) {
62        StringBuilder argTypes = new StringBuilder();
63        if (constructorArgTypes != null) {
64          for (Class<?> argType : constructorArgTypes) {
65            argTypes.append(argType.getSimpleName());
66            argTypes.append(",");
67          }
68        }
69        StringBuilder argValues = new StringBuilder();
70        if (constructorArgs != null) {
71          for (Object argValue : constructorArgs) {
72            argValues.append(String.valueOf(argValue));
73            argValues.append(",");
74          }
75        }
76        throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values ("
77            + argValues + "). Cause: " + e, e);
78      }
79    }
80  
81    private Class<?> resolveInterface(Class<?> type) {
82      Class<?> classToCreate;
83      if (type == List.class || type == Collection.class) {
84        classToCreate = LinkedList.class;
85      } else if (type == Map.class) {
86        classToCreate = LinkedHashMap.class;
87      } else if (type == SortedSet.class) { // issue #510 Collections Support
88        classToCreate = TreeSet.class;
89      } else if (type == Set.class) {
90        classToCreate = HashSet.class;
91      } else {
92        classToCreate = type;
93      }
94      return classToCreate;
95    }
96  
97    @Override
98    public <T> boolean isCollection(Class<T> type) {
99      return CustomCollection.class.isAssignableFrom(type);
100   }
101 
102   @SuppressWarnings("unchecked")
103   public <T> T[] createArray(Class<T> type, int size) {
104     return (T[]) Array.newInstance(type, size);
105   }
106 
107 }