最近在做一个代码生成的项目,使用的是jet2,感觉比较容易学习和上手。今天发现在使用自己的schema来限定input xml model时(通过xsi:noNamespaceSchemaLocation="test.xsd" 来限定schema),总是报NullPointer exception。经过一番调查发现,jet在input xml model没有schema定义时,所有input xml model中的element用AnyType来表示,如果input xml model有schema定义,jet就将所有的element加载成EObject。在jet将xpath变量转换为EObject对象时,对null的检查不够仔细。看EObjectInspector中方法:
private Object[] getFeatureValue(EObject eObject, EStructuralFeature feature)
{
(1)Object objResult = eObject.eGet(feature);
if(feature instanceof EReference) {
if(feature.isMany()) {
return ((List)objResult).toArray();
} else {
(2)return new Object[] {objResult};
}
} else {
// its an EAttribute, wrap...
final Setting setting = ((InternalEObject)eObject).eSetting(feature);
if(feature.isMany())
{
Object[] result = new Object[((List)objResult).size()];
for(int j = 0; j < result.length; j++ ) {
result[j] = new EMFEAttrAsElementWrapper(setting, j);
}
return result;
}
else
{
return new Object[] {new EMFEAttrAsElementWrapper(setting)};
}
}
}
我觉得问题出在粗斜体两行,在标有(1)的一行,返回eObject对象中的EStructurealFeature feature,对于eObjects所属的类是可以包含feature的,可是在eObject类实例里面就不一定包含feature,所以这行可以返回null,在标有(2)那行,jet没有判断objResult是否为null就返回了,也就是说返回的是new Object[]{null},这就不对了,返回之后就有可能出问题。再举个例子,比如
判断datasource下是否有connection标签如果有将它存在变量connection里面在console里面打印标签名,如果datasource里没有connection标签,if tag里面的内容将不被处理。在IfTag类的public boolean doEvalCondition()方法里,有一句
boolean processContents = XPathUtil.xpathBoolean(rawObject);
这行代码判断rawObject的size是否大于0,如果大于0返回true,processContents就为true这样if tag里面的内容就被处理,如果在前面所列的代码中返回new Object[]{null},这是一个size为1的数组,唯一的成员为null,这个满足size大于0,于是processContents为true,if tag的内容被执行,所以在执行 时,就会报connection为空,NullPointer就出来了。