use of org.apache.tapestry5.plastic.PlasticClassTransformer in project tapestry-5 by apache.
the class StrategyBuilderImpl method createProxy.
private <S> S createProxy(final Class<S> interfaceType, final StrategyRegistry<S> registry) {
ClassInstantiator instantiator = proxyFactory.createProxy(interfaceType, new PlasticClassTransformer() {
@Override
public void transform(PlasticClass plasticClass) {
final PlasticField registryField = plasticClass.introduceField(StrategyRegistry.class, "registry").inject(registry);
Class<?> interfaceSelectorType = null;
for (final Method method : interfaceType.getMethods()) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 0) {
throw new IllegalArgumentException("Invalid method " + method + ", when using the strategy pattern, every method must take at least the selector as its parameter");
}
Class<?> methodSelectorType = parameterTypes[0];
if (interfaceSelectorType == null) {
interfaceSelectorType = methodSelectorType;
} else if (!interfaceSelectorType.equals(methodSelectorType)) {
throw new IllegalArgumentException("Conflicting method definitions," + " expecting the first argument of every method to have the same type");
}
plasticClass.introduceMethod(new MethodDescription(method), new InstructionBuilderCallback() {
@Override
public void doBuild(InstructionBuilder builder) {
Class returnType = method.getReturnType();
builder.loadThis().getField(registryField);
// Argument 0 is the selector used to find the adapter and should be an object reference,
// not a primitive.
builder.loadArgument(0);
// Use the StrategyRegistry to get the adapter to re-invoke the method on
builder.invoke(StrategyRegistry.class, Object.class, "getByInstance", Object.class).checkcast(interfaceType);
// That leaves the correct adapter on top of the stack. Get the
// selector and the rest of the arguments in place and invoke the method.
builder.loadArguments().invoke(interfaceType, returnType, method.getName(), method.getParameterTypes());
builder.returnResult();
}
});
}
plasticClass.addToString(String.format("<Strategy for %s>", interfaceType.getName()));
}
});
return interfaceType.cast(instantiator.newInstance());
}
use of org.apache.tapestry5.plastic.PlasticClassTransformer in project tapestry-5 by apache.
the class ChainBuilderImpl method build.
@Override
@SuppressWarnings("unchecked")
public <T> T build(final Class<T> commandInterface, List<T> commands) {
// Jump through some hoops to convert the list into an array of the proper type
Object[] array = (Object[]) Array.newInstance(commandInterface, commands.size());
final Object[] commandsArray = commands.toArray(array);
ClassInstantiator<T> instantiator = proxyFactory.createProxy(commandInterface, new PlasticClassTransformer() {
@Override
public void transform(PlasticClass plasticClass) {
PlasticField commandsField = plasticClass.introduceField(commandsArray.getClass(), "commands").inject(commandsArray);
for (Method method : commandInterface.getMethods()) {
if (!Modifier.isStatic(method.getModifiers())) {
implementMethod(plasticClass, method, commandsField);
}
}
plasticClass.addToString(String.format("<Command chain of %s>", commandInterface.getName()));
}
});
return instantiator.newInstance();
}
use of org.apache.tapestry5.plastic.PlasticClassTransformer in project tapestry-5 by apache.
the class ThunkCreatorImpl method createInstantiator.
private <T> ClassInstantiator<T> createInstantiator(final Class<T> interfaceType) {
return proxyFactory.createProxy(interfaceType, new PlasticClassTransformer() {
@Override
public void transform(PlasticClass plasticClass) {
final PlasticField objectCreatorField = plasticClass.introduceField(ObjectCreator.class, "creator").injectFromInstanceContext();
PlasticMethod delegateMethod = plasticClass.introducePrivateMethod(interfaceType.getName(), "delegate", null, null);
delegateMethod.changeImplementation(new InstructionBuilderCallback() {
@Override
public void doBuild(InstructionBuilder builder) {
builder.loadThis().getField(objectCreatorField);
builder.invoke(CREATE_OBJECT);
builder.checkcast(interfaceType).returnResult();
}
});
for (Method method : interfaceType.getMethods()) {
plasticClass.introduceMethod(method).delegateTo(delegateMethod);
}
if (!plasticClass.isMethodImplemented(PlasticUtils.TO_STRING_DESCRIPTION)) {
final PlasticField descriptionField = plasticClass.introduceField(String.class, "description").injectFromInstanceContext();
plasticClass.introduceMethod(PlasticUtils.TO_STRING_DESCRIPTION, new InstructionBuilderCallback() {
@Override
public void doBuild(InstructionBuilder builder) {
builder.loadThis().getField(descriptionField).returnResult();
}
});
}
}
});
}
use of org.apache.tapestry5.plastic.PlasticClassTransformer in project tapestry-5 by apache.
the class ClojureBuilderImpl method build.
@Override
public <T> T build(final Class<T> interfaceType) {
assert interfaceType != null;
assert interfaceType.isInterface();
Namespace annotation = interfaceType.getAnnotation(Namespace.class);
if (annotation == null) {
throw new IllegalArgumentException(String.format("Interface type %s does not have the Namespace annotation.", interfaceType.getName()));
}
final String namespace = annotation.value();
ClassInstantiator<T> instantiator = proxyFactory.createProxy(interfaceType, new PlasticClassTransformer() {
@Override
public void transform(PlasticClass plasticClass) {
for (final Method m : interfaceType.getMethods()) {
bridgeToClojure(plasticClass, m);
}
}
private void bridgeToClojure(final PlasticClass plasticClass, final Method method) {
final MethodDescription desc = new MethodDescription(method);
if (method.getReturnType() == void.class) {
throw new IllegalArgumentException(String.format("Method %s may not be void when bridging to Clojure functions.", desc));
}
final Symbol symbol = mapper.mapMethod(namespace, method);
tracker.run(String.format("Mapping %s method %s to Clojure function %s", interfaceType.getName(), desc.toShortString(), symbol.toString()), new Runnable() {
@Override
public void run() {
Symbol namespaceSymbol = Symbol.create(symbol.getNamespace());
REQUIRE.invoke(namespaceSymbol);
IFn clojureFunction = Clojure.var(symbol);
final PlasticField fnField = plasticClass.introduceField(IFn.class, method.getName() + "IFn").inject(clojureFunction);
plasticClass.introduceMethod(desc).changeImplementation(new InstructionBuilderCallback() {
@Override
public void doBuild(InstructionBuilder builder) {
bridgeToClojure(builder, desc, fnField);
}
});
}
});
}
private void bridgeToClojure(InstructionBuilder builder, MethodDescription description, PlasticField ifnField) {
builder.loadThis().getField(ifnField);
int count = description.argumentTypes.length;
Class[] invokeParameterTypes = new Class[count];
for (int i = 0; i < count; i++) {
invokeParameterTypes[i] = Object.class;
builder.loadArgument(i).boxPrimitive(description.argumentTypes[i]);
}
Method ifnMethod = null;
try {
ifnMethod = IFn.class.getMethod("invoke", invokeParameterTypes);
} catch (NoSuchMethodException ex) {
throw new RuntimeException(String.format("Unable to find correct IFn.invoke() method: %s", ExceptionUtils.toMessage(ex)), ex);
}
builder.invoke(ifnMethod);
builder.castOrUnbox(description.returnType);
builder.returnResult();
}
});
return instantiator.newInstance();
}
Aggregations