In-depth introduction to Mybatis series 4-configuration details of the type Aliases alias (mybatis source)

Keywords: Python Mybatis Attribute xml Java

Note: This article is reproduced from Nan Ke Meng

In the previous article, "Deep and Simple Mybatis Series (3) - Configuration Detailed Properties and Environments" (Mybatis Source Chapter), we introduced properties and environments. This article continues to talk about one of the remaining configuration nodes: type Aliases. The typeAliases node is mainly used to set aliases. In fact, this is a very useful function. By configuring aliases, we do not need to specify the complete package name, and can also take aliases.

For example, when we use com.demo.entity. UserEntity, we can configure an alias user directly, so that when we use com.demo.entity. UserEntity in the configuration file later, we can use User directly.

Let's take the example above and see how typeAliases is configured.

TypeeAliases configuration

<configuration>
    <typeAliases>
      <!--
      With package, you can specify the name of the package directly, and mybatis automatically scans the JavaBeans under the package you specify.
      And by default, an alias is set with the default name: javabean's initials lowercase unqualified class name as its alias.
      You can also add a comment @Alias to javabean to customize aliases, such as: @Alias(user) 
      <package name="com.dy.entity"/>
       -->
      <typeAlias alias="UserEntity" type="com.dy.entity.User"/>
  </typeAliases>
  
  ......
  
</configuration>

Write another piece of test code to see if it works: (I only write a pseudocode)

Configuration con = sqlSessionFactory.getConfiguration();
Map<String, Class<?>> typeMap = con.getTypeAliasRegistry().getTypeAliases();
for(Entry<String, Class<?>> entry: typeMap.entrySet()) {
    System.out.println(entry.getKey() + " ================> " 
    + entry.getValue().getSimpleName());
}

The above gives you a brief introduction to the use of typeAliases, and then look at the source code in Mybatis.

The old rule begins with an analysis of xml:

TypeeAliases source code

/**
 * Resolving typeAliases nodes
 */
private void typeAliasesElement(XNode parent) {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        //If the child node is a package, the name attribute of the package node is obtained, and mybatis scans the specified package.
        if ("package".equals(child.getName())) {
          String typeAliasPackage = child.getStringAttribute("name");
          /**
          * TypeAliasRegistry Responsible for the management of aliases, which is registered through TypeAlias Registry.
          * Here's a look at the TypeAlias Registry source code
          */
          configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
        } else {
          //If the child node is a typeAlias node, the alias attribute and the type attribute value are obtained.
          String alias = child.getStringAttribute("alias");
          String type = child.getStringAttribute("type");
          try {
            Class<?> clazz = Resources.classForName(type);
            if (alias == null) {
              typeAliasRegistry.registerAlias(clazz);
            } else {
              typeAliasRegistry.registerAlias(alias, clazz);
            }
          } catch (ClassNotFoundException e) {
            throw new BuilderException("Error registering typeAlias for '" 
        + alias + "'. Cause: " + e, e);
          }
        }
      }
    }
  }

The important source code is here!

TypeAlias Registry source code

public class TypeAliasRegistry {
  
  /**
   * That's where the core is. Originally, the alias was implemented only through a HashMap. 
   * key For aliases, value is the type corresponding to the alias (class object)
   */
  private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();

  /**
   * Here are the aliases that mybatis registers for us by default
   */
  public TypeAliasRegistry() {
    registerAlias("string", String.class);

    registerAlias("byte", Byte.class);
    registerAlias("long", Long.class);
    registerAlias("short", Short.class);
    registerAlias("int", Integer.class);
    registerAlias("integer", Integer.class);
    registerAlias("double", Double.class);
    registerAlias("float", Float.class);
    registerAlias("boolean", Boolean.class);

    registerAlias("byte[]", Byte[].class);
    registerAlias("long[]", Long[].class);
    registerAlias("short[]", Short[].class);
    registerAlias("int[]", Integer[].class);
    registerAlias("integer[]", Integer[].class);
    registerAlias("double[]", Double[].class);
    registerAlias("float[]", Float[].class);
    registerAlias("boolean[]", Boolean[].class);

    registerAlias("_byte", byte.class);
    registerAlias("_long", long.class);
    registerAlias("_short", short.class);
    registerAlias("_int", int.class);
    registerAlias("_integer", int.class);
    registerAlias("_double", double.class);
    registerAlias("_float", float.class);
    registerAlias("_boolean", boolean.class);

    registerAlias("_byte[]", byte[].class);
    registerAlias("_long[]", long[].class);
    registerAlias("_short[]", short[].class);
    registerAlias("_int[]", int[].class);
    registerAlias("_integer[]", int[].class);
    registerAlias("_double[]", double[].class);
    registerAlias("_float[]", float[].class);
    registerAlias("_boolean[]", boolean[].class);

    registerAlias("date", Date.class);
    registerAlias("decimal", BigDecimal.class);
    registerAlias("bigdecimal", BigDecimal.class);
    registerAlias("biginteger", BigInteger.class);
    registerAlias("object", Object.class);

    registerAlias("date[]", Date[].class);
    registerAlias("decimal[]", BigDecimal[].class);
    registerAlias("bigdecimal[]", BigDecimal[].class);
    registerAlias("biginteger[]", BigInteger[].class);
    registerAlias("object[]", Object[].class);

    registerAlias("map", Map.class);
    registerAlias("hashmap", HashMap.class);
    registerAlias("list", List.class);
    registerAlias("arraylist", ArrayList.class);
    registerAlias("collection", Collection.class);
    registerAlias("iterator", Iterator.class);

    registerAlias("ResultSet", ResultSet.class);
  }

  
  /**
   * Processing aliases, just take them out of the hashMap that holds them.
   */
  @SuppressWarnings("unchecked")
  public <T> Class<T> resolveAlias(String string) {
    try {
      if (string == null) return null;
      String key = string.toLowerCase(Locale.ENGLISH); // issue #748
      Class<T> value;
      if (TYPE_ALIASES.containsKey(key)) {
        value = (Class<T>) TYPE_ALIASES.get(key);
      } else {
        value = (Class<T>) Resources.classForName(string);
      }
      return value;
    } catch (ClassNotFoundException e) {
      throw new TypeException("Could not resolve type alias '" 
        + string + "'.  Cause: " + e, e);
    }
  }
  
  /**
   * When configuring a package in a configuration file, this method is called to scan JavaBeans according to the configuration name.
   * The alias is then automatically registered, and by default the Bean's unqualified class name in lowercase is used as its alias
   * You can also add a comment @Alias to javabean to customize aliases, such as: @Alias(user)
   */
  public void registerAliases(String packageName){
    registerAliases(packageName, Object.class);
  }

  public void registerAliases(String packageName, Class<?> superType){
    ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
    for(Class<?> type : typeSet){
      // Ignore inner classes and interfaces (including package-info.java)
      // Skip also inner classes. See issue #6
      if (!type.isAnonymousClass() 
        && !type.isInterface() 
        && !type.isMemberClass()) {
        registerAlias(type);
      }
    }
  }

  public void registerAlias(Class<?> type) {
    String alias = type.getSimpleName();
    Alias aliasAnnotation = type.getAnnotation(Alias.class);
    if (aliasAnnotation != null) {
      alias = aliasAnnotation.value();
    } 
    registerAlias(alias, type);
  }

  /**
  * This is the essential way to register aliases. It's really just adding value to hashMap that keeps aliases.
  * Ha ha, the realization of aliases is too simple, right?
  */
  public void registerAlias(String alias, Class<?> value) {
    if (alias == null) throw new TypeException("The parameter alias cannot be null");
    String key = alias.toLowerCase(Locale.ENGLISH); // issue #748
    if (TYPE_ALIASES.containsKey(key) 
        && TYPE_ALIASES.get(key) != null 
        && !TYPE_ALIASES.get(key).equals(value)) {
      throw new TypeException("The alias '" + alias 
      + "' is already mapped to the value '" 
      + TYPE_ALIASES.get(key).getName() + "'.");
    }
    TYPE_ALIASES.put(key, value);
  }

  public void registerAlias(String alias, String value) {
    try {
      registerAlias(alias, Resources.classForName(value));
    } catch (ClassNotFoundException e) {
      throw new TypeException("Error registering type alias "
        +alias+" for "+value+". Cause: " + e, e);
    }
  }
  
  /**
   * Gets the HashMap that holds the alias name, and the Configuration object holds a reference to the TypeAlias Registry.
   * So, if necessary, we can get it through the Configuration object
   */
  public Map<String, Class<?>> getTypeAliases() {
    return Collections.unmodifiableMap(TYPE_ALIASES);
  }

}

As can be seen from the source code, the principle of setting aliases is so simple. Mybatis defaults to set us many aliases, which can be seen in the code above.

Well, the content of this article is so simple, so far. The next section will continue with the configuration nodes that have not yet been explained.

Posted by jumphopper on Fri, 24 May 2019 14:27:37 -0700