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.reflection.factory;
17  
18  import java.io.Serializable;
19  import java.lang.reflect.Constructor;
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Optional;
28  import java.util.Set;
29  import java.util.SortedSet;
30  import java.util.TreeSet;
31  import java.util.stream.Collectors;
32  
33  import org.apache.ibatis.reflection.ReflectionException;
34  import org.apache.ibatis.reflection.Reflector;
35  
36  /**
37   * @author Clinton Begin
38   */
39  public class DefaultObjectFactory implements ObjectFactory, Serializable {
40  
41    private static final long serialVersionUID = -8855120656740914948L;
42  
43    @Override
44    public <T> T create(Class<T> type) {
45      return create(type, null, null);
46    }
47  
48    @SuppressWarnings("unchecked")
49    @Override
50    public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
51      Class<?> classToCreate = resolveInterface(type);
52      // we know types are assignable
53      return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
54    }
55  
56    private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
57      try {
58        Constructor<T> constructor;
59        if (constructorArgTypes == null || constructorArgs == null) {
60          constructor = type.getDeclaredConstructor();
61          try {
62            return constructor.newInstance();
63          } catch (IllegalAccessException e) {
64            if (Reflector.canControlMemberAccessible()) {
65              constructor.setAccessible(true);
66              return constructor.newInstance();
67            } else {
68              throw e;
69            }
70          }
71        }
72        constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));
73        try {
74          return constructor.newInstance(constructorArgs.toArray(new Object[0]));
75        } catch (IllegalAccessException e) {
76          if (Reflector.canControlMemberAccessible()) {
77            constructor.setAccessible(true);
78            return constructor.newInstance(constructorArgs.toArray(new Object[0]));
79          } else {
80            throw e;
81          }
82        }
83      } catch (Exception e) {
84        String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
85            .stream().map(Class::getSimpleName).collect(Collectors.joining(","));
86        String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
87            .stream().map(String::valueOf).collect(Collectors.joining(","));
88        throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
89      }
90    }
91  
92    protected Class<?> resolveInterface(Class<?> type) {
93      Class<?> classToCreate;
94      if (type == List.class || type == Collection.class || type == Iterable.class) {
95        classToCreate = ArrayList.class;
96      } else if (type == Map.class) {
97        classToCreate = HashMap.class;
98      } else if (type == SortedSet.class) { // issue #510 Collections Support
99        classToCreate = TreeSet.class;
100     } else if (type == Set.class) {
101       classToCreate = HashSet.class;
102     } else {
103       classToCreate = type;
104     }
105     return classToCreate;
106   }
107 
108   @Override
109   public <T> boolean isCollection(Class<T> type) {
110     return Collection.class.isAssignableFrom(type);
111   }
112 
113 }