Skip to content

Commit 67e3ec3

Browse files
committed
Fix BeanIntrospection to handle primitive types in property lookup
Fixes #12079 - Added helper methods isAssignableFrom() and getWrapperType() to properly handle primitive-to-wrapper type conversion - Updated getProperty(), getReadProperty(), and getWriteProperty() methods to use the new helper - Primitive types are now converted to their wrapper equivalents before assignability checking - Resolves IntrospectionException when using Micronaut Mapper with primitive types All existing mapper tests pass with no regressions.
1 parent d80a91b commit 67e3ec3

File tree

1 file changed

+34
-3
lines changed

1 file changed

+34
-3
lines changed

core/src/main/java/io/micronaut/core/beans/BeanIntrospection.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ default <P> BeanWriteProperty<T, P> getRequiredWriteProperty(@NonNull String nam
304304
ArgumentUtils.requireNonNull("type", type);
305305

306306
final BeanProperty<T, ?> prop = getProperty(name).orElse(null);
307-
if (prop != null && type.isAssignableFrom(prop.getType())) {
307+
if (prop != null && isAssignableFrom(type, prop.getType())) {
308308
//noinspection unchecked
309309
return Optional.of((BeanProperty<T, P>) prop);
310310
}
@@ -324,7 +324,7 @@ default <P> BeanWriteProperty<T, P> getRequiredWriteProperty(@NonNull String nam
324324
ArgumentUtils.requireNonNull("type", type);
325325

326326
final BeanReadProperty<T, ?> prop = getReadProperty(name).orElse(null);
327-
if (prop != null && type.isAssignableFrom(prop.getType())) {
327+
if (prop != null && isAssignableFrom(type, prop.getType())) {
328328
//noinspection unchecked
329329
return Optional.of((BeanReadProperty<T, P>) prop);
330330
}
@@ -345,7 +345,7 @@ default <P> BeanWriteProperty<T, P> getRequiredWriteProperty(@NonNull String nam
345345
ArgumentUtils.requireNonNull("type", type);
346346

347347
final BeanWriteProperty<T, ?> prop = getWriteProperty(name).orElse(null);
348-
if (prop != null && type.isAssignableFrom(prop.getType())) {
348+
if (prop != null && isAssignableFrom(type, prop.getType())) {
349349
//noinspection unchecked
350350
return Optional.of((BeanProperty<T, P>) prop);
351351
}
@@ -490,4 +490,35 @@ interface Builder<T> {
490490
*/
491491
@NonNull T build(Object... params);
492492
}
493+
494+
/**
495+
* Helper method to check if a source type is assignable to a target type,
496+
* properly handling primitive types by converting them to their wrapper types.
497+
*
498+
* @param targetType The target type to check assignability to
499+
* @param sourceType The source type to check assignability from
500+
* @return true if the source type is assignable to the target type
501+
*/
502+
static boolean isAssignableFrom(Class<?> targetType, Class<?> sourceType) {
503+
Class<?> actualSourceType = sourceType.isPrimitive() ? getWrapperType(sourceType) : sourceType;
504+
return targetType.isAssignableFrom(actualSourceType);
505+
}
506+
507+
/**
508+
* Helper method to get the wrapper type for a primitive type.
509+
*
510+
* @param primitiveType The primitive type
511+
* @return The corresponding wrapper type, or the original type if not primitive
512+
*/
513+
static Class<?> getWrapperType(Class<?> primitiveType) {
514+
if (primitiveType == boolean.class) return Boolean.class;
515+
if (primitiveType == byte.class) return Byte.class;
516+
if (primitiveType == char.class) return Character.class;
517+
if (primitiveType == short.class) return Short.class;
518+
if (primitiveType == int.class) return Integer.class;
519+
if (primitiveType == long.class) return Long.class;
520+
if (primitiveType == float.class) return Float.class;
521+
if (primitiveType == double.class) return Double.class;
522+
return primitiveType; // Not a primitive, return as-is
523+
}
493524
}

0 commit comments

Comments
 (0)