天天看点

一个没有创建默认构造函数,引发的mybatis报错。导致No constructor found in com.leo.course.scheduling.domain

2019-03-06 20:57:51.290 DEBUG 13588 --- [p-nio-81-exec-4] c.l.c.s.m.D.getPageQueryList             : ==>  Preparing: select id,depno,depname,majorno,majorname,addtime,flag from department where id limit ?,? 

2019-03-06 20:57:51.290 DEBUG 13588 --- [p-nio-81-exec-4] c.l.c.s.m.D.getPageQueryList             : ==> Parameters: 0(Integer), 10(Integer)

2019-03-06 20:57:51.294 ERROR 13588 --- [p-nio-81-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.ExecutorException: No constructor found in com.leo.course.scheduling.domain.Department matching [java.lang.Integer, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.sql.Timestamp, java.lang.String]] with root cause

org.apache.ibatis.executor.ExecutorException: No constructor found in com.leo.course.scheduling.domain.Department matching [java.lang.Integer, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.sql.Timestamp, java.lang.String]

有上面打印的信息来说是没有提供默认的构造函数,可是我已经书写了有参的构造函数,看下面的实体类,

package com.leo.course.scheduling.domain;

import java.util.Date;

import org.springframework.format.annotation.DateTimeFormat;

import com.fasterxml.jackson.annotation.JsonFormat;

public class Department {
	private Integer id;
	private String depno;
	private String depname;
	private String majorno;
	private String majorname;
	private String flag;
	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	@JsonFormat(pattern = "yyyy-MM-dd", timezone="GMT+8")
	private Date addtime;
	/**
	 * @return the id
	 */
	public Integer getId() {
		return id;
	}
	/**
	 * @param id the id to set
	 */
	public void setId(Integer id) {
		this.id = id;
	}
	/**
	 * @return the depno
	 */
	public String getDepno() {
		return depno;
	}
	/**
	 * @param depno the depno to set
	 */
	public void setDepno(String depno) {
		this.depno = depno;
	}
	/**
	 * @return the depname
	 */
	public String getDepname() {
		return depname;
	}
	/**
	 * @param depname the depname to set
	 */
	public void setDepname(String depname) {
		this.depname = depname;
	}
	/**
	 * @return the majorno
	 */
	public String getMajorno() {
		return majorno;
	}
	/**
	 * @param majorno the majorno to set
	 */
	public void setMajorno(String majorno) {
		this.majorno = majorno;
	}
	/**
	 * @return the majorname
	 */
	public String getMajorname() {
		return majorname;
	}
	/**
	 * @param majorname the majorname to set
	 */
	public void setMajorname(String majorname) {
		this.majorname = majorname;
	}
	/**
	 * @return the flag
	 */
	public String getFlag() {
		return flag;
	}
	/**
	 * @param flag the flag to set
	 */
	public void setFlag(String flag) {
		this.flag = flag;
	}
	/**
	 * @return the addtime
	 */
	public Date getAddtime() {
		return addtime;
	}
	/**
	 * @param addtime the addtime to set
	 */
	public void setAddtime(Date addtime) {
		this.addtime = addtime;
	}
	public Department(Integer id, String depno, String depname, String majorno, String majorname, String flag,
			Date addtime) {
		super();
		this.id = id;
		this.depno = depno;
		this.depname = depname;
		this.majorno = majorno;
		this.majorname = majorname;
		this.flag = flag;
		this.addtime = addtime;
	}
	/**
	 * 没有这这个构造函数,为何不能默认加入呢
	 
	public Department() {
		super();
	}
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Department [id=" + id + ", depno=" + depno + ", depname=" + depname + ", majorno=" + majorno
				+ ", majorname=" + majorname + ", flag=" + flag + ", addtime=" + addtime + "]";
	}
	
	
}
           

为什么会出现这样的错误呢,原来是xml中返回的是resultType中设定了返回的是这个实体类而这个ResultType是通过DefaultResultSetHandler这个类进行对resultType进行解析的,其中咱们主要看其中的主要代码:

private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs,
                                              String columnPrefix) throws SQLException {
    final Constructor<?>[] constructors = resultType.getDeclaredConstructors();
    final Constructor<?> annotatedConstructor = findAnnotatedConstructor(constructors);
    if (annotatedConstructor != null) {
      return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix, annotatedConstructor);
    } else {
      for (Constructor<?> constructor : constructors) {
        if (allowedConstructor(constructor, rsw.getClassNames())) {
          return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix, constructor);
        }
      }
    }
    throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
  }
           

其中源码中创建构造函数签名这个类中,必须要通过反射获取声明的构造者:

final Constructor<?>[] constructors = resultType.getDeclaredConstructors();

先是要判断是否构造函数为空,不为空的话创建这个构造函数,如果为空,先进行对其进行遍历,如果是允许这个构造函数的者进行使用,如果不符合上面的规则,抛出异常,    throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());

使用这个构造函数进行创建是主要使用其构造函数,说明了这里并没有使用new出对象,因为new的时候必定会加入这个默认构造器而这里是通过反射获取的所以不能为其自动加入这个构造器,所以这就是问题的最终原因,只需要把构造器函数给写出来。

在看下反射类中的所获得对象的构造方法

publicConstructor<T> getConstructor(Class<?>... parameterTypes):获取单个构造方法,参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象

  publicConstructor<T> getDeclaredConstructor(Class<?>... parameterTypes):获取单个构造方法(能获取私有的,但要用Constructor类的setAccessible方法设置访问权限),参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象

所以条件都不能够满足所以出现异常。

继续阅读