Hogo Parses MyBatis Source (8) - TypeAlias Registry (Type Alias Registry) of Type Type Module

The original works can be reproduced, but please indicate the address of the origin: http://www.cnblogs.com/V1haoge/p/6705769.html

1. Review

Data source module and previous transaction module are all part of environment, while environment is the foundation of Configuration and the cornerstone of Configuration, but the cornerstone is only to build a simple configuration object, which needs more to adapt to the actual use environment. Outside the component, these things need to be added to the configuration object, this time introduce the type module - Type.

The specific content of the type module is basically under the package of org.apache.ibatis.type. The type module also includes a lot of content, mainly the type alias registers and type processor registers, which are used to plan all types of aliases and type processors as a whole, and then the two registers will be added. Instances are configurated to the Configuration object; besides that, they are basically implementation classes of specific type processors. MyBatis has a very comprehensive type processor implementation built in. Of course, we can also customize the implementation of type processors, which can take effect after simple configuration.

In this article, we only study the type alias registry TypeAlias Registry.

2. Type Alias

What is a type alias?

The type alias in MyBatis is to set aliases for commonly used types in MyBatis, using aliases instead of specific types. In short, the specific types are saved in a HashMap with aliases as keys for easy access.

What is the use of type aliases?

Type aliases in MyBatis are mainly used to replace complex fully qualified type names and to set up parameter types and return result types in mapper configuration files. MyBatis parses parameter type aliases to obtain specific parameter types before and after database operations. The result type alias is parsed to get the specific result type, and then the parameters and results are matched and mapped respectively by type processing of the type processor to be studied later.

2.1 Basic Type Aliases

What are the built-in aliases in MyBatis? Let's look at the source code:

 1 //Built-in type aliases for registration systems in constructors  
 2 public TypeAliasRegistry() {
 3         //String type
 4     registerAlias("string", String.class);
 5 
 6     //Basic Packaging Types
 7     registerAlias("byte", Byte.class);
 8     registerAlias("long", Long.class);
 9     registerAlias("short", Short.class);
10     registerAlias("int", Integer.class);
11     registerAlias("integer", Integer.class);
12     registerAlias("double", Double.class);
13     registerAlias("float", Float.class);
14     registerAlias("boolean", Boolean.class);
15 
16     //Basic Array Packaging Types
17     registerAlias("byte[]", Byte[].class);
18     registerAlias("long[]", Long[].class);
19     registerAlias("short[]", Short[].class);
20     registerAlias("int[]", Integer[].class);
21     registerAlias("integer[]", Integer[].class);
22     registerAlias("double[]", Double[].class);
23     registerAlias("float[]", Float[].class);
24     registerAlias("boolean[]", Boolean[].class);
25 
26     //Adding an underscore becomes the basic type.
27     registerAlias("_byte", byte.class);
28     registerAlias("_long", long.class);
29     registerAlias("_short", short.class);
30     registerAlias("_int", int.class);
31     registerAlias("_integer", int.class);
32     registerAlias("_double", double.class);
33     registerAlias("_float", float.class);
34     registerAlias("_boolean", boolean.class);
35 
36     //Adding an underscore becomes the basic array type
37     registerAlias("_byte[]", byte[].class);
38     registerAlias("_long[]", long[].class);
39     registerAlias("_short[]", short[].class);
40     registerAlias("_int[]", int[].class);
41     registerAlias("_integer[]", int[].class);
42     registerAlias("_double[]", double[].class);
43     registerAlias("_float[]", float[].class);
44     registerAlias("_boolean[]", boolean[].class);
45 
46     //Date numeric type
47     registerAlias("date", Date.class);
48     registerAlias("decimal", BigDecimal.class);
49     registerAlias("bigdecimal", BigDecimal.class);
50     registerAlias("biginteger", BigInteger.class);
51     registerAlias("object", Object.class);
52 
53     registerAlias("date[]", Date[].class);
54     registerAlias("decimal[]", BigDecimal[].class);
55     registerAlias("bigdecimal[]", BigDecimal[].class);
56     registerAlias("biginteger[]", BigInteger[].class);
57     registerAlias("object[]", Object[].class);
58 
59     //Aggregate type
60     registerAlias("map", Map.class);
61     registerAlias("hashmap", HashMap.class);
62     registerAlias("list", List.class);
63     registerAlias("arraylist", ArrayList.class);
64     registerAlias("collection", Collection.class);
65     registerAlias("iterator", Iterator.class);
66 
67     //There's another one. ResultSet type
68     registerAlias("ResultSet", ResultSet.class);
69  }     

From the source code above, we can see that a large number of basic type aliases have been registered in the parametric constructor of the type alias registry class TypeAlias Registry.

String type (alias similar to string)

2. Basic type wrapper type and its array type (aliases like byte, byte [])

3. Basic types and their array types (aliases like _byte,_byte[])

4. Date type and its array type (aliases like date, date [])

5. Types of large numbers and their array types (aliases like bigdecimal, BigDecimal [])

6.Object type and its array type (aliases like object, object [])

7. Collection types (aliases like collection, map, list, hsahmap, arraylist, iterator)

ResultSet result set type (alias ResultSet)

Note: This is not all of MyBatis's built-in type aliases, and some of them are registered in its no-parameter constructor when creating a Configuration instance, which is not covered here.

2.2 Built-in Method

MyBatis defines the access method of HashMap, a set of type aliases, in the TypeAlias Registry class:

2.2.1 Storage Method-Registration Method

The core type alias registration method in a class is the registerAlias (String alias, Class <?> value) method:

 1     //Registration type alias
 2   public void registerAlias(String alias, Class<?> value) {
 3     if (alias == null) {
 4       throw new TypeException("The parameter alias cannot be null");
 5     }
 6     // issue #748
 7     String key = alias.toLowerCase(Locale.ENGLISH);
 8     //If it already exists key Yes, and value Inconsistent with previous reports
 9     //Here the logic is a little complicated, it feels unnecessary, one key For one value Ah, there is key You can't just make a direct error report.
10     if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
11       throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
12     }
13     TYPE_ALIASES.put(key, value);
14   }

The core registration method above is very simple. The parameters are the alias name to be set and the class type to be matched. TYPE_ALIASES is the HashMap set defined in the registry to save the type alias:

1   private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();

But this is only the core method, and its periphery is also enclosed by two ways of registration, one is the unified registration of packages, the other is the way of registration one by one. Both methods are designed for user-defined alias registration.

2.2.1.1 Package Uniform Registration Method

This method corresponds to the following settings:

1  <typeAliases>
2      <package name="com.xx.xx.xx"/>
3  </typeAliases>

Details of registration can be found in the following source code:

 1   public void registerAliases(String packageName){
 2     registerAliases(packageName, Object.class);
 3   }
 4 
 5     //Scan and register all inherited packages superType Type aliases of
 6   public void registerAliases(String packageName, Class<?> superType){
 7         //TODO ResolverUtil
 8     ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
 9     resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
10     Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
11     for(Class<?> type : typeSet){
12       // Ignore inner classes and interfaces (including package-info.java)
13       // Skip also inner classes. See issue #6
14       if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
15         registerAlias(type);
16       }
17     }
18   }
19 
20     //Registration type alias
21   public void registerAlias(Class<?> type) {
22     //If there is no type alias, use Class.getSimpleName To register
23     String alias = type.getSimpleName();
24     //Or through Alias Annotations to register(Class.getAnnotation)
25     Alias aliasAnnotation = type.getAnnotation(Alias.class);
26     if (aliasAnnotation != null) {
27       alias = aliasAnnotation.value();
28     } 
29     registerAlias(alias, type);
30   }

Analysis:

The above three methods are called one by one, and then the core registration method is invoked for the final registration. Let's see the purpose of these three methods.

In the first method, there is only one code to register all classes under the specified package name. It calls the second method. The second parameter is to limit the source of the class to be registered. Only classes inherited from a given type can be registered. The assignment of Object.class means that all classes under it are registered under an alias. Scope of consideration.

The second method is more complicated. The purpose of this method is to limit the scope of classes to register aliases. First, the parameter superClass is used to restrict the type alias registration only for classes inherited from this class, and then the internal classes (including anonymous internal classes, ordinary internal classes) and interface classes are excluded. By calling the third method, the remaining specified type is registered as a type alias.

Note: The second method uses ResolverUtil, a tool class defined in MyBatis, to implement the search find() and getClasses() methods for the type below the specified package name.

The third method is mainly used to set aliases. There are two cases. The first one is to get the Alias name of the type through Class.getSimpleName() method for the type without explicitly specifying the Alias name. It actually gets the name of the type in lowercase initials, and the other is to make use of @Alia. The s annotation explicitly specifies the type of the Alias name (value), directly obtains the value of the value in the annotation as the Alias name, and finally calls the core registration method to register the type Alias.

Each of the above three methods has its own functions. The first method obtains package names from outside, the second restriction scope, and the third method sets aliases. We can either specify aliases explicitly without specifying them or use annotations to specify aliases explicitly without specifying that the last alias will call local methods to obtain them.

2.2.1.2 One-by-one registration

This method aims at the following settings:

1  <typeAliases>
2      <typeAlias type="com.xxx.xx.Role" alias="role" />
3  </typeAliases>

Details of registration can be found in the source code:

1   public void registerAlias(String alias, String value) {
2     try {
3       registerAlias(alias, Resources.classForName(value));
4     } catch (ClassNotFoundException e) {
5       throw new TypeException("Error registering type alias "+alias+" for "+value+". Cause: " + e, e);
6     }
7   }

Analysis:

This method is very simple, mainly because the target and alias names have been specified in the settings, so it only needs to directly implement the core registration method to complete the registration work. This method is suitable for a small number of types of registration, but once there are more types of registration, the work will be obvious. It's very complicated and tedious. In order to simplify our work, we can adopt the first way before. To adopt this way, we need to place the classes which need to register type aliases under a unified package intentionally when encoding the architecture.

2.2.2 Selection Method-Analytical Method

First, list the method source code:

 1   public <T> Class<T> resolveAlias(String string) {
 2     try {
 3       if (string == null) {
 4         return null;
 5       }
 6       // issue #748
 7       //First convert to lowercase and then parse
 8       //There are also small letters here. bug?See 748 bug(stay google code upper)
 9       //https://code.google.com/p/mybatis/issues
10       //For example, if the local language is Turkish,that i It's not capitalized. I Yes, it's another character.(İ). So the Turkish machine won't work. mybatis Now! This is a big one. bug,But basically everyone does.......
11       String key = string.toLowerCase(Locale.ENGLISH);
12       Class<T> value;
13       //The principle is very simple. HashMap Find the corresponding key value and return the type alias. Class
14       if (TYPE_ALIASES.containsKey(key)) {
15         value = (Class<T>) TYPE_ALIASES.get(key);
16       } else {
17         //I can't find it. Try again. String Direct conversion Class(No wonder we can use it directly. java.lang.Integer The way to define, can also be on int Definition)
18         value = (Class<T>) Resources.classForName(string);
19       }
20       return value;
21     } catch (ClassNotFoundException e) {
22       throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + e, e);
23     }
24   }

Analysis:

Combining with the annotation content, we can see that the so-called parsing alias is to obtain the corresponding value of the alias stored in the collection through the alias, that is, the class type.

Note that if a given alias (alias key) can be found in the collection, the corresponding type will be returned directly, but if no alias can be found, an attempt will be made to convert the alias directly to the type, and the alias that can be converted must be the string form of the fully qualified name of the corresponding type (for example, "java" Lang. Integer is an alias for schema, which is the way we can write "int" or "java.lang.Integer" when we set parameterType and ResultType in the mapper file. Because the alias resolution method resolveAlias() is called when parsing the alias here, the correct parsing can be achieved in both cases.

3. Modular Analysis

The so-called module analysis is one of my new contents, mainly studying the purpose of setting up a module, the status and role of this module in the whole MyBatis system architecture, this part of the content is completely my understanding, if there are deviations and shortcomings, please don't hesitate to give advice, I will correct it in time.

Type aliases are also an important part of MyBatis's architecture, which is usually used in conjunction with type processors. It is used in the label properties of the configuration SQL script in the mapper configuration file. Here is a simple example:

1 <delete id="delete" parameterType="int">
2     DELETE TB_USER u WHERE u.use_id = #{useId}
3 </delete>
4 <select id="select" parameterType="int" resulttype="com.xxx.xx.User">
5     SELECT * FROM TB_USER u WHERE u.use_id=#{useId}
6 </select>

The values of parameterType and resultType in the example above are type aliases. They all appear as strings and are used as keys in parsing methods to obtain the corresponding class type values in HashMap, or directly convert them into corresponding types.

This widget is a key component of the mapper module, because we configure the mapper in the form of XML, it is unavoidable that there is no real Java type in the XML file, most of which are strings, so we need to add a given type string in MyBatis to parse the XML mapping configuration. Method to get the Java type it represents. (The string here is the type alias)

XML mapper is a mapping transformation between Java type and database type to realize ORM function.

In this way, we understand the location and role of type alias registers in MyBatis as a whole.

(Author: The Only Hogo)

Keywords: Java Mybatis xml Database

Added by focus310 on Tue, 09 Jul 2019 21:31:15 +0300