Java Map toString() 其中映射值是接口

Java Map toString() where Map Value is Interface

我的方法中有很多类型的地图。我试图制作一个 mapToString() 方法来处理它们,但我的一些地图将接口作为它们的键值。

    public <T> String interfaceToString(Class<T> clazz, Object instance) {
        log.info(clazz + "");

        StringBuilder toString = new StringBuilder("[ " + clazz.getSimpleName() + " - ");

        List<Method> methods = Arrays.asList(clazz.getDeclaredMethods());

        methods.forEach(method -> {
            try {
                toString.append(method.getName() + ": " + method.invoke(instance) + ", ");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        });

        toString.replace(toString.length() - 2, toString.length() - 1, "");
        toString.append("]");

        return toString.toString();

    }

    public <T> String mapToString(Map<T, ?> map) {
        StringBuilder toString = new StringBuilder("[ ");

        for (T key : map.keySet()) {
            Object value = map.get(key);
            if (value.getClass().isInterface()) {
                toString.append(interfaceToString(value.getClass(), value));
            } else {
                toString.append("[" + key + ", " + value + "] ");
            }
        }

        toString.append(" ]");

        return toString.toString();
    }

它适用于常规地图,但它只打印键值为接口的地图的对象表示。我正在使用许多接口,因为我正在使用 Spring JPA 投影来拉回我的数据库表的部分部分。

当我调试时,当我在 mapToString 中记录 value.getClass() 时,它的 class 是一个代理。这就是附加到 StringBuilder 时 isInterface() 检查失败的原因。

有更好的方法吗?

编辑

这是我的界面。这是一个 Spring JPA 存储库投影。

public interface OrderGetOpenReceievablesAndHistoryView {

    Integer getNo();

    String getBillchCode();

    String getBilltlCode();

}

这是我的地图:

Map<Integer, OrderGetOpenReceievablesAndHistoryView> carrierOrders = new HashMap<>();

我将地图的键指定为一个整数,它的值是 OrderGetOpenReceievablesAndHistoryView。

carrierOrders = orderRepository.findOpenRecievablesHistoryViewByNoIn(carrierOrderNos).stream().collect(Collectors.toMap(OrderGetOpenReceievablesAndHistoryView::getNo, Function.identity()));

我想从 interfaceToString() 方法将 OrderGetOpenReceievablesAndHistoryView 值打印为普通字符串。

EDIT2

所以,我真正想要的是一种打印出其值为接口的地图的方法。如果我这样做,它会很好地打印出来:

for (Integer key : carrierOrders.keySet()) {
    OrderGetOpenReceievablesAndHistoryView value = carrierOrders.get(key);
    log.info("{} : {}, {}, {}", key, value.getBillchCode(), value.getBilltlCode(), value.getNo());
}

因为我正在处理可能有数百个值可以是任何值的地图,所以我不想每次打印它们时都必须编写这个循环。

这是每个循环的正则输出:

104432581 : TAXZ443237, HJMU499371, 104432581

这是 mapToString 方法 () 的输出:

[104406075, org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap@750bef00]

每个对象都是具体 class 的实例,因此 value.getClass().isInterface() 永远不会计算为 true。当您想要对编译时已知的接口类型进行特殊处理时,即在泛型类型中声明的映射值类型,您必须将其作为参数传递给方法。

例如

public static <V> String mapToString(Map<?,V> map, Class<? super V> valueType) {
    StringBuilder toString = new StringBuilder("[ ");
    for(Map.Entry<?,V> entry: map.entrySet()) {
        toString.append(entry.getKey()).append(": ");
        if(!valueType.isInterface()) toString.append(entry.getValue());
        else appendInterface(toString, valueType, entry.getValue());
        toString.append(", ");
    }
    if(toString.length() > 2) toString.setLength(toString.length() - 2);
    return toString.append(" ]").toString();
}

private static <V> void appendInterface(
                   StringBuilder toString, Class<V> valueType, V value) {

    toString.append("[ ").append(valueType.getSimpleName()).append(" - ");
    for(Method m: valueType.getDeclaredMethods()) {
        if(!Modifier.isStatic(m.getModifiers()) && m.getParameterCount() == 0) {
            Object o;
            try {
                o = m.invoke(value);
            } catch(ReflectiveOperationException e) {
                e.printStackTrace();
                continue;
            }
            toString.append(m.getName()).append(": ").append(o).append(", ");
        }
    }
    toString.replace(toString.length() - 2, toString.length(), "]");
}

你可以像这样调用

Map<Integer, OrderGetOpenReceievablesAndHistoryView> carrierOrders = new HashMap<>();

String s = mapToString(carrierOrders, OrderGetOpenReceievablesAndHistoryView.class);