mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2026-05-29 18:57:11 +08:00
fix: BeanConverter和MapConverter对源Bean使用isReadableBean替代isBean
修了 #4245 的问题。当 List 里的元素类用了 @Setter(AccessLevel.PROTECTED) 只有 protected setter 的时候,BeanUtil.copyProperties 会抛 ConvertException: Unsupported source type,但实际上这个类有 public getter, 作为源对象完全可以被读取。 原因是 BeanConverter 和 MapConverter 在处理源对象时用 isBean() 做检查, 但 isBean() 看的是有没有 public setter,这是判断"能不能写"的标准, 而源对象需要的是"能不能读"。BeanUtil 里其实已经有 isReadableBean() 方法 (检查 public getter),正好适合这个场景,换过来就行。两个转换器各改了一行, 另外补了两个单测覆盖这种情况。
This commit is contained in:
@@ -79,7 +79,7 @@ public class BeanConverter<T> extends AbstractConverter<T> {
|
||||
|
||||
if(value instanceof Map ||
|
||||
value instanceof ValueProvider ||
|
||||
BeanUtil.isBean(value.getClass())) {
|
||||
BeanUtil.isReadableBean(value.getClass())) {
|
||||
if(value instanceof Map && this.beanClass.isInterface()) {
|
||||
// 将Map动态代理为Bean
|
||||
return MapProxy.create((Map<?, ?>)value).toProxyBean(this.beanClass);
|
||||
|
||||
@@ -73,7 +73,7 @@ public class MapConverter extends AbstractConverter<Map<?, ?>> {
|
||||
map = MapUtil.createMap(mapClass);
|
||||
}
|
||||
convertMapToMap((Map) value, map);
|
||||
} else if (BeanUtil.isBean(value.getClass())) {
|
||||
} else if (BeanUtil.isReadableBean(value.getClass())) {
|
||||
if(value.getClass().getName().equals("cn.hutool.json.JSONArray")){
|
||||
// issue#3795 增加JSONArray转Map错误检查
|
||||
throw new UnsupportedOperationException(StrUtil.format("Unsupported {} to Map.", value.getClass().getName()));
|
||||
|
||||
@@ -974,4 +974,85 @@ public class BeanUtilTest {
|
||||
final boolean bean = BeanUtil.isBean(Dict.class);
|
||||
assertFalse(bean);
|
||||
}
|
||||
|
||||
// ============ Test for GitHub issue #4245 ============
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Order4245 {
|
||||
private Long orderId;
|
||||
private String orderNo;
|
||||
private List<OrderItem4245> orderItemList;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter(AccessLevel.PROTECTED)
|
||||
@AllArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@NoArgsConstructor
|
||||
public static class OrderItem4245 {
|
||||
private Long itemId;
|
||||
private String productName;
|
||||
private Integer quantity;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class OrderDto4245 {
|
||||
private Long orderId;
|
||||
private String orderNo;
|
||||
private List<OrderItemDto4245> orderItemList;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class OrderItemDto4245 {
|
||||
private Long itemId;
|
||||
private String productName;
|
||||
private Integer quantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* GitHub issue#4245: BeanUtil.copyProperties throws ConvertException
|
||||
* when source list element has protected setters.
|
||||
*
|
||||
* <p>Root cause: BeanConverter used isBean() (which checks for public setters)
|
||||
* on the SOURCE object instead of isReadableBean() (which checks for public getters).
|
||||
* A source bean only needs to be readable, not writable.</p>
|
||||
*/
|
||||
@Test
|
||||
public void issue4245Test() {
|
||||
final Order4245 order = new Order4245(
|
||||
1L,
|
||||
"01",
|
||||
new ArrayList<>()
|
||||
);
|
||||
order.getOrderItemList().add(
|
||||
new OrderItem4245(1L, "aa", 1)
|
||||
);
|
||||
|
||||
// This should not throw ConvertException
|
||||
final OrderDto4245 dto = BeanUtil.copyProperties(order, OrderDto4245.class);
|
||||
|
||||
assertNotNull(dto);
|
||||
assertEquals(order.getOrderId(), dto.getOrderId());
|
||||
assertEquals(order.getOrderNo(), dto.getOrderNo());
|
||||
assertNotNull(dto.getOrderItemList());
|
||||
assertEquals(1, dto.getOrderItemList().size());
|
||||
assertEquals(Long.valueOf(1L), dto.getOrderItemList().get(0).getItemId());
|
||||
assertEquals("aa", dto.getOrderItemList().get(0).getProductName());
|
||||
assertEquals(Integer.valueOf(1), dto.getOrderItemList().get(0).getQuantity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test map conversion with protected setter bean
|
||||
*/
|
||||
@Test
|
||||
public void issue4245MapConvertTest() {
|
||||
final OrderItem4245 item = new OrderItem4245(1L, "aa", 1);
|
||||
// Should not throw UnsupportedOperationException
|
||||
final Map<String, Object> map = BeanUtil.beanToMap(item);
|
||||
assertNotNull(map);
|
||||
assertEquals(1L, map.get("itemId"));
|
||||
assertEquals("aa", map.get("productName"));
|
||||
assertEquals(1, map.get("quantity"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user