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);
我的方法中有很多类型的地图。我试图制作一个 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);