Search in sources :

Example 1 with PlasticClassTransformer

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());
}
Also used : PlasticClass(org.apache.tapestry5.plastic.PlasticClass) InstructionBuilder(org.apache.tapestry5.plastic.InstructionBuilder) ClassInstantiator(org.apache.tapestry5.plastic.ClassInstantiator) StrategyRegistry(org.apache.tapestry5.commons.util.StrategyRegistry) MethodDescription(org.apache.tapestry5.plastic.MethodDescription) Method(java.lang.reflect.Method) PlasticClassTransformer(org.apache.tapestry5.plastic.PlasticClassTransformer) PlasticField(org.apache.tapestry5.plastic.PlasticField) PlasticClass(org.apache.tapestry5.plastic.PlasticClass) InstructionBuilderCallback(org.apache.tapestry5.plastic.InstructionBuilderCallback)

Example 2 with PlasticClassTransformer

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();
}
Also used : PlasticClass(org.apache.tapestry5.plastic.PlasticClass) PlasticClassTransformer(org.apache.tapestry5.plastic.PlasticClassTransformer) PlasticField(org.apache.tapestry5.plastic.PlasticField) Method(java.lang.reflect.Method)

Example 3 with PlasticClassTransformer

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();
                    }
                });
            }
        }
    });
}
Also used : PlasticClass(org.apache.tapestry5.plastic.PlasticClass) InstructionBuilder(org.apache.tapestry5.plastic.InstructionBuilder) PlasticClassTransformer(org.apache.tapestry5.plastic.PlasticClassTransformer) PlasticField(org.apache.tapestry5.plastic.PlasticField) PlasticMethod(org.apache.tapestry5.plastic.PlasticMethod) PlasticMethod(org.apache.tapestry5.plastic.PlasticMethod) Method(java.lang.reflect.Method) InstructionBuilderCallback(org.apache.tapestry5.plastic.InstructionBuilderCallback)

Example 4 with PlasticClassTransformer

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();
}
Also used : Symbol(clojure.lang.Symbol) Method(java.lang.reflect.Method) Namespace(org.apache.tapestry5.clojure.Namespace) IFn(clojure.lang.IFn)

Aggregations

Method (java.lang.reflect.Method)4 PlasticClass (org.apache.tapestry5.plastic.PlasticClass)3 PlasticClassTransformer (org.apache.tapestry5.plastic.PlasticClassTransformer)3 PlasticField (org.apache.tapestry5.plastic.PlasticField)3 InstructionBuilder (org.apache.tapestry5.plastic.InstructionBuilder)2 InstructionBuilderCallback (org.apache.tapestry5.plastic.InstructionBuilderCallback)2 IFn (clojure.lang.IFn)1 Symbol (clojure.lang.Symbol)1 Namespace (org.apache.tapestry5.clojure.Namespace)1 StrategyRegistry (org.apache.tapestry5.commons.util.StrategyRegistry)1 ClassInstantiator (org.apache.tapestry5.plastic.ClassInstantiator)1 MethodDescription (org.apache.tapestry5.plastic.MethodDescription)1 PlasticMethod (org.apache.tapestry5.plastic.PlasticMethod)1