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.type;
17  
18  import java.math.BigDecimal;
19  import java.math.BigInteger;
20  import java.sql.ResultSet;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Date;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Locale;
29  import java.util.Map;
30  import java.util.Set;
31  
32  import org.apache.ibatis.io.ResolverUtil;
33  import org.apache.ibatis.io.Resources;
34  
35  /**
36   * @author Clinton Begin
37   */
38  public class TypeAliasRegistry {
39  
40    private final Map<String, Class<?>> typeAliases = new HashMap<>();
41  
42    public TypeAliasRegistry() {
43      registerAlias("string", String.class);
44  
45      registerAlias("byte", Byte.class);
46      registerAlias("char", Character.class);
47      registerAlias("character", Character.class);
48      registerAlias("long", Long.class);
49      registerAlias("short", Short.class);
50      registerAlias("int", Integer.class);
51      registerAlias("integer", Integer.class);
52      registerAlias("double", Double.class);
53      registerAlias("float", Float.class);
54      registerAlias("boolean", Boolean.class);
55  
56      registerAlias("byte[]", Byte[].class);
57      registerAlias("char[]", Character[].class);
58      registerAlias("character[]", Character[].class);
59      registerAlias("long[]", Long[].class);
60      registerAlias("short[]", Short[].class);
61      registerAlias("int[]", Integer[].class);
62      registerAlias("integer[]", Integer[].class);
63      registerAlias("double[]", Double[].class);
64      registerAlias("float[]", Float[].class);
65      registerAlias("boolean[]", Boolean[].class);
66  
67      registerAlias("_byte", byte.class);
68      registerAlias("_char", char.class);
69      registerAlias("_character", char.class);
70      registerAlias("_long", long.class);
71      registerAlias("_short", short.class);
72      registerAlias("_int", int.class);
73      registerAlias("_integer", int.class);
74      registerAlias("_double", double.class);
75      registerAlias("_float", float.class);
76      registerAlias("_boolean", boolean.class);
77  
78      registerAlias("_byte[]", byte[].class);
79      registerAlias("_char[]", char[].class);
80      registerAlias("_character[]", char[].class);
81      registerAlias("_long[]", long[].class);
82      registerAlias("_short[]", short[].class);
83      registerAlias("_int[]", int[].class);
84      registerAlias("_integer[]", int[].class);
85      registerAlias("_double[]", double[].class);
86      registerAlias("_float[]", float[].class);
87      registerAlias("_boolean[]", boolean[].class);
88  
89      registerAlias("date", Date.class);
90      registerAlias("decimal", BigDecimal.class);
91      registerAlias("bigdecimal", BigDecimal.class);
92      registerAlias("biginteger", BigInteger.class);
93      registerAlias("object", Object.class);
94  
95      registerAlias("date[]", Date[].class);
96      registerAlias("decimal[]", BigDecimal[].class);
97      registerAlias("bigdecimal[]", BigDecimal[].class);
98      registerAlias("biginteger[]", BigInteger[].class);
99      registerAlias("object[]", Object[].class);
100 
101     registerAlias("map", Map.class);
102     registerAlias("hashmap", HashMap.class);
103     registerAlias("list", List.class);
104     registerAlias("arraylist", ArrayList.class);
105     registerAlias("collection", Collection.class);
106     registerAlias("iterator", Iterator.class);
107 
108     registerAlias("ResultSet", ResultSet.class);
109   }
110 
111   @SuppressWarnings("unchecked")
112   // throws class cast exception as well if types cannot be assigned
113   public <T> Class<T> resolveAlias(String string) {
114     try {
115       if (string == null) {
116         return null;
117       }
118       // issue #748
119       String key = string.toLowerCase(Locale.ENGLISH);
120       Class<T> value;
121       if (typeAliases.containsKey(key)) {
122         value = (Class<T>) typeAliases.get(key);
123       } else {
124         value = (Class<T>) Resources.classForName(string);
125       }
126       return value;
127     } catch (ClassNotFoundException e) {
128       throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + e, e);
129     }
130   }
131 
132   public void registerAliases(String packageName) {
133     registerAliases(packageName, Object.class);
134   }
135 
136   public void registerAliases(String packageName, Class<?> superType) {
137     ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
138     resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
139     Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
140     for (Class<?> type : typeSet) {
141       // Ignore inner classes and interfaces (including package-info.java)
142       // Skip also inner classes. See issue #6
143       if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
144         registerAlias(type);
145       }
146     }
147   }
148 
149   public void registerAlias(Class<?> type) {
150     String alias = type.getSimpleName();
151     Alias aliasAnnotation = type.getAnnotation(Alias.class);
152     if (aliasAnnotation != null) {
153       alias = aliasAnnotation.value();
154     }
155     registerAlias(alias, type);
156   }
157 
158   public void registerAlias(String alias, Class<?> value) {
159     if (alias == null) {
160       throw new TypeException("The parameter alias cannot be null");
161     }
162     // issue #748
163     String key = alias.toLowerCase(Locale.ENGLISH);
164     if (typeAliases.containsKey(key) && typeAliases.get(key) != null && !typeAliases.get(key).equals(value)) {
165       throw new TypeException(
166           "The alias '" + alias + "' is already mapped to the value '" + typeAliases.get(key).getName() + "'.");
167     }
168     typeAliases.put(key, value);
169   }
170 
171   public void registerAlias(String alias, String value) {
172     try {
173       registerAlias(alias, Resources.classForName(value));
174     } catch (ClassNotFoundException e) {
175       throw new TypeException("Error registering type alias " + alias + " for " + value + ". Cause: " + e, e);
176     }
177   }
178 
179   /**
180    * Gets the type aliases.
181    *
182    * @return the type aliases
183    *
184    * @since 3.2.2
185    */
186   public Map<String, Class<?>> getTypeAliases() {
187     return Collections.unmodifiableMap(typeAliases);
188   }
189 
190 }