public static void implementPropertyValueProvider()

in plastic/src/main/java/org/apache/tapestry5/plastic/PlasticUtils.java [255:375]


    public static void implementPropertyValueProvider(PlasticClass plasticClass, Set<FieldInfo> fieldInfos)
    {
        
        final Set<PlasticMethod> methods = plasticClass.introduceInterface(PropertyValueProvider.class);
        
        final InstructionBuilderCallback getterCallback = (builder) -> {
            
            for (FieldInfo field : fieldInfos) 
            {
                builder.loadArgument(0);
                builder.loadConstant(field.name);
                builder.invokeVirtual(String.class.getName(), "boolean", "equals", Object.class.getName());
                builder.when(Condition.NON_ZERO, ifBuilder -> 
                {
                    final String prefix = field.type.equals("boolean") ? "is" : "get";
                    final String methodName = prefix + PlasticInternalUtils.capitalize(field.name);
                    
                    ifBuilder.loadThis();
                    builder.invokeVirtual(
                            plasticClass.getClassName(), 
                            field.type, 
                            methodName);
                    ifBuilder.boxPrimitive(field.type);
                    ifBuilder.returnResult();
                });
                
            }
            
            // Field/property not found, so let's try the superclass in case
            // it also implement
            
            builder.loadThis();
            builder.instanceOf(PropertyValueProvider.class);
            
            builder.when(Condition.NON_ZERO, ifBuilder -> {
                builder.loadThis();
                builder.loadArgument(0);
                ifBuilder.invokeSpecial(
                        plasticClass.getSuperClassName(), 
                        PROPERTY_VALUE_PROVIDER_GETTER_METHOD_DESCRIPTION);
                ifBuilder.returnResult();
            });
            
            // Giving up
            
            builder.throwException(RuntimeException.class, "Property not found or not supported");
            
        };
        
        final InstructionBuilderCallback setterCallback = (builder) -> {
            
            for (FieldInfo field : fieldInfos) 
            {
                builder.loadArgument(0);
                builder.loadConstant(field.name);
                builder.invokeVirtual(String.class.getName(), "boolean", "equals", Object.class.getName());
                builder.when(Condition.NON_ZERO, ifBuilder -> 
                {
                    final String methodName = "set" + PlasticInternalUtils.capitalize(field.name);
                    
                    ifBuilder.loadThis();
                    ifBuilder.loadArgument(1);
                    ifBuilder.castOrUnbox(field.type);
                    ifBuilder.invokeVirtual(
                            plasticClass.getClassName(), 
                            void.class.getName(), 
                            methodName,
                            field.type);
                    ifBuilder.returnResult();
                });
                
            }
            
            // Field/property not found, so let's try the superclass in case
            // it also implement
            
            builder.loadThis();
            builder.instanceOf(PropertyValueProvider.class);
            
            builder.when(Condition.NON_ZERO, ifBuilder -> {
                builder.loadThis();
                builder.loadArgument(0);
                builder.loadArgument(1);
                ifBuilder.invokeSpecial(
                        plasticClass.getSuperClassName(), 
                        PROPERTY_VALUE_PROVIDER_SETTER_METHOD_DESCRIPTION);
                ifBuilder.returnResult();
            });
            
            // Giving up
            
            builder.throwException(RuntimeException.class, "Property not found or not supported");
            
        };
        
        final PlasticMethod getterMethod;
        final PlasticMethod setterMethod;
        
        // Superclass has already defined this method, so we need to override it so
        // it can also find the subclasses' declared fields/properties.
        if (methods.isEmpty())
        {
            getterMethod = plasticClass.introduceMethod(PROPERTY_VALUE_PROVIDER_GETTER_METHOD_DESCRIPTION, getterCallback);
            setterMethod = plasticClass.introduceMethod(PROPERTY_VALUE_PROVIDER_SETTER_METHOD_DESCRIPTION, setterCallback);
        }
        else
        {
            getterMethod = methods.stream()
                    .filter(m -> m.getDescription().methodName.equals(GETTER_METHOD_NAME))
                    .findFirst()
                    .get();
            setterMethod = methods.stream()
                    .filter(m -> m.getDescription().methodName.equals(SETTER_METHOD_NAME))
                    .findFirst()
                    .get();
        }
        
        getterMethod.changeImplementation(getterCallback);
        setterMethod.changeImplementation(setterCallback);
        
    }