Skip to content

Provide certain support for constructor methods that contain generics #3508

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 2 commits into from

Conversation

guanchengang
Copy link

No description provided.

@epochcoder
Copy link
Contributor

Hi @guanchengang ,the recently merged 101 should fix this issue with constructor injection. Did you try with 3.6.0 snapshot?

@guanchengang
Copy link
Author

Thank you for your reply @epochcoder , the constructor injection fix in 101 is related to collections.
Like the situation below:
CountResult.java

public class CountResult<T> {
  private Long id;
  private T count;
  
  public CountResult(Long id, T count) {
    this.id = id;
    this.count = count;
  }
  
  // getter setter...
}

TestMapper.java

public interface TestMapper {
  List<CountResult<Integer>> countGroupByUid();
}

some configurations in TestMapper.xml

<select id="countGroupByUid" resultMap="resMap">
  SELECT
    uid as id,
    count(*) as count
  FROM t_test
  GROUP BY uid
</select>

<resultMap id="resMap" type="com.example.CountResult">
  <constructor>
    <arg column="id" javaType="java.lang.Long"/>
    <arg column="count" javaType="java.lang.Integer" />
  </constructor>
</resultMap>

At this point, mybatis will directly throw a NoSuchMethodException, but clearly, this instance should be constructible. Moreover, users who configure resMap are aware of what they are doing. Do you think it's necessary for mybatis to handle this situation? If not, I'll close this PR.

@epochcoder
Copy link
Contributor

Hey @guanchengang, Indeed you are right; collection injection will only work if a collection is present in the constructor. Regardless, I see now that it won't take care of this generic condition in this case.

Given that there is not runtime information on the type (always Object.class) this will assume (as you said) the user knows what they are doing.

I'll defer to @harawata on this one.

@harawata
Copy link
Member

harawata commented Aug 2, 2025

Thank you for the PR, @guanchengang ,

If you use a result map with the DefaultObjectFactory, the javaTypes should match the actual parameter types of the target constructor. i.e.

<constructor>
  <arg column="id" javaType="java.lang.Long" />
  <!-- Due to type erasure, the actual type is Object -->
  <arg column="count" javaType="java.lang.Object" typeHandler="org.apache.ibatis.type.IntegerTypeHandler" />
</constructor>

If you really want this behavior (i.e. searching for viable constructor on every instantiation), you can create/use a custom object factory, but it is not a good implementation for the default one, IMHO.

Also, if your object is relatively simple, you should try auto-mapping because it performs similar constructor search.

@guanchengang
Copy link
Author

Thank you for your reply. @harawata
You're right, modifying the default implementation is not a good approach. The solution you provided is already sufficient to meet my needs. I will close this pr. If I have a better way in the future, I will create a new pr.

@guanchengang guanchengang deleted the generic-support branch August 4, 2025 00:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants