Java Map toString(),其中Map值为Interface。

问题描述 投票:0回答:1

我的方法中有很多类型的地图。我试着做了一个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 Projections来拉回数据库表的部分内容。

当我在调试时,当我在mapToString中记录value.getClass()时,它的类是一个Proxy。这就是为什么在追加到StringBuilder时,isInterface()检查失败的原因。

有没有更好的方法?

EDIT

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

public interface OrderGetOpenReceievablesAndHistoryView {

    Integer getNo();

    String getBillchCode();

    String getBilltlCode();

}

这是我的地图。

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

我把地图的key赋值为一个Integer,把它的值赋值为OrderGetOpenReceievablesAndHistoryView.

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

我想把OrderGetOpenReceievablesAndHistoryView的值从interfaceToString()方法中打印成一个普通的字符串。

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]
java reflection spring-data-jpa hashmap tostring
1个回答
2
投票

每一个对象都是一个具体的类的实例,所以说 value.getClass().isInterface() 不外乎 true. 当你想对一个在编译时已知的接口类型进行特殊处理时,即在通用类型中声明的map的值类型,你必须把它作为一个参数传递给方法。

例如

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);
© www.soinside.com 2019 - 2024. All rights reserved.