String fieldName = "$type$" + _parameterName;
cf.addField(Constants.ACC_PRIVATE | Constants.ACC_STATIC, _classType, fieldName);
MethodFabricator mf = cf.getStaticInitializerMethod();
InstructionFactory factory = cf.getInstructionFactory();
String className = cf.getClassName();
Type throwableType = _factory.getObjectType(Throwable.class.getName());
mf.append(factory.createGetStatic(className, fieldName, _classType));
BranchInstruction ifNotNullBI = new IFNONNULL(null);
mf.append(ifNotNullBI);
// Invoke Class.forName and store ther result.
// Concern: will the class be visible to the right class loader?
// May need to use alternate forName() and pass Thread's context class loader.
mf.append(new PUSH(cf.getConstantPool(), _typeClassName));
InstructionHandle tryStart =
mf.append(
factory.createInvoke(
"java.lang.Class",
"forName",
_classType,
new Type[] { Type.STRING },
Constants.INVOKESTATIC));
mf.append(factory.createPutStatic(className, fieldName, _classType));
GOTO jumpOut = new GOTO(null);
InstructionHandle tryEnd = mf.append(jumpOut);
String exceptionClassName = ApplicationRuntimeException.class.getName();
InstructionHandle catchHandle = mf.append(factory.createNew(exceptionClassName));
// This stuff can make my head spin, so let's map it out a little.
// CCE = ClassCastException, ARE = ApplicationRuntimeException
// Stack: CCE, ARE --> ARE, CCE, ARE
mf.append(InstructionConstants.DUP_X1);
// Stack: ARE, CCE, ARE -> ARE, ARE, CCE
mf.append(InstructionConstants.SWAP);
mf.append(
factory.createInvoke(
exceptionClassName,
Constants.CONSTRUCTOR_NAME,
Type.VOID,
new Type[] { throwableType },
Constants.INVOKESPECIAL));