MyBatis version
3.5.11
Steps to reproduce
class MyType {
final String computed;
public MyType(Integer i) {
this.computed = i + "";
}
}
@Select("...")
@ConstructorArgs({ @Arg(column = "...", name = "i") })
List<MyType> select();
Expected result
MyBatis should understand that i
is expected to be of type Integer
given it's the type of the matching argument in the constructor.
Actual result
I get in the logs:
Found a constructor with arg names [i], but the type of 'i' did not match. Specified: [java.lang.Object] Declared: [java.lang.Integer]
I believe this is due to the fact that MapperAnnotationBuilder#applyConstructorArgs
calls MapperBuilderAssistant#buildResultMapping
, which tries to resolve the Java type by looking at the class' fields, instead of by looking at the constructor args as one could think given @ConstructorArgs
is used.
In my example, because MyType
doesn't have a field named i
, only a constructor arg, then it doesn't successfully resolve the type of i
and defaults to Object
(see MapperBuilderAssistant#resolveResultJavaType
).
I believe when @ConstructorArgs
is used, then implicit type resolution should be run against the constructor arguments.
Workaround
Explicitly specify the Java type to use:
@Arg(column = "i", name = "i", javaType = Integer.class)
Side notes
Relates to #2207, although not exactly the same case I believe.
Comment From: sp00m
Just FYI, another perhaps related issue: @MappedTypes
on top of a TypeHandler
isn't taken into account when @ConstructorArgs
is used without explicitly specifying the Java types. I'm not 100% sure whether it should though.
In a nutshell, building upon my above example:
@MappedTypes({ Integer.class })
class CustomIntegerHandler implements TypeHandler<Integer> { }
@ConstructorArgs({ @Arg(column = "...", name = "i", typeHandler = CustomIntegerHandler.class ) })
This fails too with the same message as above, because the specified typeHandler
isn't used when trying to resolve the type of i
, which I believe it should.
Let me know if you believe this deserves its own ticket.
Comment From: harawata
Hello @sp00m ,
Constructors are identified by parameter types, not by argument names.
You can omit the javaType
only when there is a writable property with the same name and type.
It's explained in the documentation.
Comment From: harawata
@sp00m ,
I have added the following statement to the error message.
Note that 'javaType' is required when there is no readable property with the same name ('name' is optional, BTW).
For constructor mappings, name
attribute is optional and is useful only when it's difficult to synchronize the argument order. See #721 .
Assuming that there is no further action needed, I'm going to close this. Thanks again for taking the time to submit the report!