in daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/layers/LayerRuntimeCompiler.scala [67:193]
private def computeLayerVarsRuntime(
lrd: LayerRuntimeData,
protoLayer: Layer
): LayerVarsRuntime = {
val optLayerVarsRuntime = alreadyCheckedLayers.get(protoLayer.name())
optLayerVarsRuntime.getOrElse {
val c = protoLayer.getClass
val constructor = c.getConstructor() // cannot fail because SPI loader would have failed
val allMethods = c.getMethods
val optParamSetter = allMethods.find { _.getName == varParamSetter }
val allVarResultGetters =
ListSet(allMethods.filter { m =>
val nom = m.getName
nom.startsWith(varResultPrefix)
}.toSeq: _*)
if (lrd.qNameToVRD.isEmpty && optParamSetter.isEmpty && allVarResultGetters.isEmpty) {
// there are no vars, so no setter, and no getter(s). We're done
new LayerVarsRuntime(constructor, None, Nil, Nil)
} else {
val allLayerVRDs = ListSet(lrd.qNameToVRD.toSeq.map(_._2): _*)
// there is either a params setter, a result getter, or both.
val paramVRDs: Seq[VariableRuntimeData] =
optParamSetter.toSeq.flatMap { paramSetter =>
// there is a param setter with args that are supposed to correspond to bound vars
// it is allowed for it to have zero args. Then it's purpose is just initialization, but it
// must still get called.
val params = paramSetter.getParameters.toSeq
val paramTypes = paramSetter.getParameterTypes.toSeq
val pVRDs: Seq[VariableRuntimeData] = (params.zip(paramTypes)).map { case (p, pt) =>
val vrd = lrd.qNameToVRD.getOrElse(
p.getName,
lrd.context.SDE(
s"No layer DFDL variable named '${p.getName}' was found in namespace ${lrd.namespace}."
)
)
val vrdClass = PrimType.toJavaType(vrd.primType.dfdlType)
lrd.context.schemaDefinitionUnless(
compatibleTypes(vrdClass, pt),
s"""Layer setter argument ${vrd.globalQName.local} and the corresponding
|Layer DFDL variable have differing types: ${pt.getName}
| and ${vrdClass.getName} respectively.""".stripMargin
)
vrd
}
// Now we deal with the result getters and the corresponding vars
//
pVRDs
}
val nParams = paramVRDs.length
val nVars = lrd.qNameToVRD.size
val returnVRDs = allLayerVRDs -- paramVRDs // set subtraction
// each returnVRD needs to have a corresponding getter method
val returnVRDNames = returnVRDs.map(_.globalQName.local)
val resultGettersNames = allVarResultGetters.map(_.getName.replace(varResultPrefix, ""))
val nResultGetters = resultGettersNames.size
val javaParamSetterArgs =
allLayerVRDs
.map { vrd =>
s"type: ${PrimType.toJavaTypeString(vrd.primType.dfdlType)} name: ${vrd.globalQName.local}"
}
.mkString(", ")
lrd.context.schemaDefinitionUnless(
nParams + nResultGetters == nVars,
s"""Layer class $c does not have a setter with arguments for each of the layer's variables.
| It should have a setter named $varParamSetter with an argument for each layer parameter, in any order, such as
| ($javaParamSetterArgs), and a getter for remaining layer variables, named with a specific
| name prefix like: ' $varResultPrefix '.""".stripMargin
)
val returnVRDsWithoutGetters = returnVRDNames -- resultGettersNames
val resultGettersWithoutVRDs = resultGettersNames -- returnVRDNames
lrd.context.schemaDefinitionUnless(
returnVRDsWithoutGetters.isEmpty,
s"""The layer variables ${returnVRDsWithoutGetters.mkString(
","
)} have no corresponding getters."""
)
lrd.context.schemaDefinitionUnless(
resultGettersWithoutVRDs.isEmpty, {
val getterFullNames = returnVRDsWithoutGetters.map { vname =>
this.varResultPrefix + vname
}
s"""The getters ${getterFullNames.mkString(
","
)} have no corresponding layer variables."""
}
)
// at this point we know each variable that was not a parameter of the setter
// has a getter with matching name.
val resultVarPairs = resultGettersNames.map { (rgn: String) =>
val getter: Method =
allVarResultGetters
.find { (g: Method) => g.getName == varResultPrefix + rgn }
.getOrElse {
Assert.invariantFailed("no getter for getter name.")
}
val vrd = returnVRDs.find { vrd => vrd.globalQName.local == rgn }.getOrElse {
Assert.invariantFailed("no vrd for getter name.")
}
(vrd, getter)
}
resultVarPairs.foreach { case (vrd, getter) =>
val vrdClass = PrimType.toJavaType(vrd.primType.dfdlType)
val gt = getter.getReturnType
lrd.context.schemaDefinitionUnless(
compatibleTypes(vrdClass, gt),
s"""Layer return variable ${vrd.globalQName.local} and the corresponding
|Layer getter have differing types: ${vrdClass.getName}
| and ${gt.getName} respectively.""".stripMargin
)
lrd.context.schemaDefinitionUnless(
getter.getParameterCount == 0,
s"""Layer return variable getter ${getter.getName} must have no arguments."""
)
}
val lrv =
new LayerVarsRuntime(constructor, optParamSetter, paramVRDs, resultVarPairs.toSeq)
alreadyCheckedLayers.put(lrd.spiName, lrv)
lrv
}
}
}