in plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java [182:319]
public PlasticClassImpl(ClassNode classNode, ClassNode implementationClassNode, PlasticClassPool pool, InheritanceData parentInheritanceData,
StaticContext parentStaticContext, boolean proxy)
{
this.classNode = classNode;
this.pool = pool;
this.proxy = proxy;
this.implementationClassNode = implementationClassNode;
staticContext = parentStaticContext.dupe();
className = PlasticInternalUtils.toClassName(classNode.name);
superClassName = PlasticInternalUtils.toClassName(classNode.superName);
int lastIndexOfDot = className.lastIndexOf('.');
String packageName = lastIndexOfDot > -1 ? className.substring(0, lastIndexOfDot) : "";
fieldInstrumentations = new FieldInstrumentations(classNode.superName);
annotationAccess = new DelegatingAnnotationAccess(pool.createAnnotationAccess(classNode.visibleAnnotations),
pool.createAnnotationAccess(superClassName));
this.parentInheritanceData = parentInheritanceData;
inheritanceData = parentInheritanceData.createChild(packageName);
for (String interfaceName : classNode.interfaces)
{
inheritanceData.addInterface(interfaceName);
}
methods = new ArrayList<>(classNode.methods.size());
String invalidConstructorMessage = invalidConstructorMessage();
for (MethodNode node : classNode.methods)
{
if (node.name.equals(CONSTRUCTOR_NAME))
{
if (node.desc.equals(NOTHING_TO_VOID))
{
originalConstructor = node;
fieldTransformMethods.add(node);
} else
{
node.instructions.clear();
newBuilder(node).throwException(IllegalStateException.class, invalidConstructorMessage);
}
continue;
}
/*
* Static methods are not visible to the main API methods, but they must still be transformed,
* in case they directly access fields. In addition, track their names to avoid collisions.
*/
if (Modifier.isStatic(node.access))
{
if (isInheritableMethod(node))
{
inheritanceData.addMethod(node.name, node.desc, node.access == 0);
}
methodNames.add(node.name);
fieldTransformMethods.add(node);
continue;
}
if (!Modifier.isAbstract(node.access))
{
fieldTransformMethods.add(node);
}
PlasticMethodImpl pmi = new PlasticMethodImpl(this, node);
methods.add(pmi);
description2method.put(pmi.getDescription(), pmi);
if (isInheritableMethod(node))
{
inheritanceData.addMethod(node.name, node.desc, node.access == 0);
}
methodNames.add(node.name);
}
methodNames.addAll(parentInheritanceData.methodNames());
Collections.sort(methods);
fields = new ArrayList<>(classNode.fields.size());
for (FieldNode node : classNode.fields)
{
fieldNames.add(node.name);
// Ignore static fields.
if (Modifier.isStatic(node.access))
continue;
// When we instrument the field such that it must be private, we'll get an exception.
fields.add(new PlasticFieldImpl(this, node));
}
Collections.sort(fields);
// TODO: Make the output class's constructor protected, and create a shim class to instantiate it
// efficiently (without reflection).
newConstructor = new MethodNode(ACC_PUBLIC, CONSTRUCTOR_NAME, CONSTRUCTOR_DESC, null, null);
constructorBuilder = newBuilder(newConstructor);
// Start by calling the super-class no args constructor
if (parentInheritanceData.isTransformed())
{
// If the parent is transformed, our first step is always to invoke its constructor.
constructorBuilder.loadThis().loadArgument(0).loadArgument(1);
constructorBuilder.invokeConstructor(superClassName, StaticContext.class.getName(),
InstanceContext.class.getName());
} else
{
// Assumes the base class includes a visible constructor that takes no arguments.
// TODO: Do a proper check for this case and throw a meaningful exception
// if not present.
constructorBuilder.loadThis().invokeConstructor(superClassName);
}
// During the transformation, we'll be adding code to the constructor to pull values
// out of the static or instance context and assign them to fields.
// Later on, we'll add the RETURN opcode
}