我的方法中有很多类型的地图。我试着做了一个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]
每一个对象都是一个具体的类的实例,所以说 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);