我为打开关于这个一般性问题的另一个问题而道歉,但我在SO上发现的问题似乎都与我的问题密切相关。
我有一个现有的工作数据流管道,它接受KV<Long, Iterable<TableRow>>
对象并输出TableRow
个对象。此代码在我们的生产环境中运行,没有问题。我现在正试图用直接转轮实现单元测试来测试这个管道,但单元测试在它到达线时失败
LinkedHashMap<String, Object> evt = (LinkedHashMap<String, Object>) row.get(Schema.EVT);
在管道中,抛出错误消息:
java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap 无法转换为java.util.LinkedHashMap
现有数据流代码的简化版本如下所示:
public static class Process extends DoFn<KV<Long, Iterable<TableRow>>, TableRow> {
/* private variables */
/* constructor */
/* private functions */
@ProcessElement
public void processElement(ProcessContext c) throws InterruptedException, ParseException {
EventProcessor eventProc = new EventProcessor();
Processor.WorkItem workItem = new Processor.WorkItem();
Iterator<TableRow> it = c.element().getValue().iterator();
// process all TableRows having the same id
while (it.hasNext()) {
TableRow item = it.next();
if (item.containsKey(Schema.EVT))
eventProc.process(item, workItem);
else
/* process by different Proc class */
}
/* do additional logic */
/* c.output() is somewhere far below */
}
}
public class EventProcessor extends Processor {
// Extract data from an event into the WorkItem
@SuppressWarnings("unchecked")
@Override
public void process(TableRow row, WorkItem item) {
try {
LinkedHashMap<String, Object> evt = (LinkedHashMap<String, Object>) row.get(Schema.EVT);
LinkedHashMap<String, Object> profile = (LinkedHashMap<String, Object>) row.get(Schema.PROFILE);
/* if no exception, process further business logic */
/* business logic */
} catch (ParseException e) {
System.err.println("Bad row");
}
}
}
单元测试的相关部分(准备Process() DoFn
的主要输入)如下所示:
Map<Long, List<TableRow>> groups = new HashMap<Long, List<TableRow>>();
List<KV<Long, Iterable<TableRow>>> collections = new ArrayList<KV<Long,Iterable<TableRow>>>();
Gson gson = new Gson();
// populate the map with events grouped by id
for(int i = 0; i < EVENTS.length; i++) {
TableRow row = gson.fromJson(EVENTS[i], TableRow.class);
Long id = EVENT_IDS[i];
if(groups.containsKey(id))
groups.get(id).add(row);
else
groups.put(id, new ArrayList<TableRow>(Arrays.asList(row)));
}
// prepare main input for pipeline
for(Long key : groups.keySet())
collections.add(KV.of(key, groups.get(key)));
导致问题的行是gson.fromJson(EVENTS[i], TableRow.class);
,它似乎将TableRow的内部表示编码为LinkedTreeMap的错误类型。
TableRow的编码类型似乎是com.google.gson.internal.LinkedTreeMap
而不是预期的java.util.LinkedHashMap
。有没有办法可以将我在单元测试中创建的TableRow转换为正确的java.util.LinkedHashMap
类型,以便单元测试成功,而不对已在生产中工作的现有数据流代码进行任何更改?
答案 0 :(得分:2)
将解决方案作为答案重新发布。
如果您不使用其特定功能,则不建议转换为具体类。在这种情况下,最好转换为Map
而不是LinkedHashMap
。 Gson的LinkedTreeMap
也是Map
,因此不会出现任何问题。
答案 1 :(得分:0)
这是因为LinkedHashMap并不优于LinkedTreeMap,因此它们可能没有相同的方法。因此,Java编译器认为以这种方式进行转换可能会导致evt
使用与row.get(Schema.EVT)
不同的方法,从而导致错误的东西。
但是,您可以将LinkedTreeMap转换为AbstractMap,Map或Object,因为它们都优于它。
所以(正如许多评论指出的那样)修复它,只需使用
Map<String, Object> evt = row.get(Schema.EVT);
你应该没事。
答案 2 :(得分:0)
我会考虑(不仅如此)投下code smell。每次对演员表进行编码时,都会冒ClassCastException
发生的风险。
正如其他人已经说过的那样,Map
界面可以像Map<String, Object> evt = row.get(Schema.EVT);
一样使用。
或者,LinkedHashMap
可以构建新的new LinkedHashMap<String, Object>(row.get(Schema.EVT));
。
第二种方法的优点是保持LinkedHashMap
类型,这可能会也可能不重要,这取决于您的情况。