Skip to content

Fix if parameterType is simple type, then throws java.lang.NoSuchMeth… #834

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

abel533
Copy link
Contributor

@abel533 abel533 commented Nov 12, 2016

Fix if parameterType is simple type, then throws java.lang.NoSuchMethodException: xxx.();

Recreate the problem, in nested query:

<resultMap id="userRoleMapSelect" extends="userMap" type="tk.mybatis.simple.model.SysUser">
	<association property="role" 
		 select="selectRoleById" 
		 javaType="tk.mybatis.simple.model.SysRole"
	         column="{id=role_id}"/>
</resultMap>
<!-- if you doesn't set parameterType, the default value is null, then it will use HashMap -->
<select id="selectRoleById" parameterType="long" 
            resultMap="tk.mybatis.simple.mapper.RoleMapper.roleMap">
    select * from sys_role where id = #{id}
</select>

the selectRoleById also can be use in annotation:

@Select({"select id,role_name roleName, enabled, create_by createBy, create_time createTime",
		 "from sys_role",
		 "where id = #{id}"})
//default parameterType is Long
SysRole selectById(Long id);

@kazuki43zoo
Copy link
Member

Hi @abel533, Thanks for contributing !!
Could you add tests ?

@kazuki43zoo
Copy link
Member

Hi @abel533 , Probably you can resolve this issue using single parameter instead of composite parameter(such as {property=column}) as follow:

<resultMap id="userRoleMapSelect" extends="userMap" type="tk.mybatis.simple.model.SysUser">
	<association property="role" 
		 select="selectRoleById" 
		 javaType="tk.mybatis.simple.model.SysRole"
-	         column="{id=role_id}"/>
+	         column="role_id"/>

@kazuki43zoo
Copy link
Member

Hi @abel533, I think your fix is not appropriate because the ObjectFactory has no responsibility for creating to an un-assignable type instance. In other words, I think should not converted to the HashMap from a simple type(such as the Long) using the ObjectFactory.

As alternative, I will propose to fix at the DefaultResultSetHandler#instantiateParameterObject method as follow:

private Object instantiateParameterObject(Class<?> parameterType) {
  if (parameterType == null) {
    return new HashMap<Object, Object>();
+ } else if (SimpleTypeRegistry.isSimpleType(parameterType)
+     || typeHandlerRegistry.hasTypeHandler(parameterType)) {
+   return new HashMap<Object, Object>();
  } else if (ParamMap.class.equals(parameterType)) {
    return new HashMap<Object, Object>(); // issue #649
  } else {
    return objectFactory.create(parameterType);
  }
}

@emacarron @harawata, What do you think about my opinion ? I want to hear everyone opinion.
Thanks.

@harawata
Copy link
Member

In that example, parameterType="long" is incorrect.
In my opinion, users should use correct parameterType or omit parameterType (parameterType is optional).

I encourage users to omit parameterType.

  • If parameterType is omitted, MyBatis uses the actual runtime parameter type.
  • If the right parameterType is specified, the result will be the same as the above.
  • If a wrong parameterType is specified, the statement will fail.

So, it is better/safer to omit parameterType.

@kazuki43zoo
Copy link
Member

@harawata , thanks you for replying !!

In my opinion, users should use correct parameterType or omit parameterType (parameterType is optional).

I encourage users to omit parameterType.

Ok, i agree with your opinion. In this case ... , we should choose from following solutions.

  • Omit the parameterType attribute on select element <- @harawata 's suggestion
  • Change to use the single parameter (column="role_id") <- my suggestion

Probably, if nested query has been implemented on @Select annotation, we should be used the single parameter model as follow:

@Results(
    @Result(property = "role", one = @One(select = "selectRoleById"), column = "role_id")
)
@Select("select * sys_user where id = #{id}")
SysUser selectUser(Long id);

@Select("select * from sys_role where id = #{id}")
SysRole selectRoleById(Long id);

@wuwen5
Copy link
Contributor

wuwen5 commented Nov 23, 2016

As mentioned here: https://github.com/mybatis/mybatis-3/blob/master/src/test/java/org/apache/ibatis/submitted/complex_column/Person.xml#L45

In that example, because it using RAW, so the paremter is a SysUser,is my understanding correct ?

@harawata
Copy link
Member

@wuwen5 ,

In that example,
When the select statement is called directly, the actual parameter is a long.
When the select statement is called as a nested select of the result map 'userRoleMapSelect', the actual parameter is a map.

Regarding the difference between raw and dynamic statement, please see Eduardo's explanation here.

@wuwen5
Copy link
Contributor

wuwen5 commented Nov 24, 2016

Thank you! @harawata.

@abel533
Copy link
Contributor Author

abel533 commented Dec 4, 2016

@kazuki43zoo I think your fix is appropriate. You can fix it in your way.
I will close this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants