Aled Sage created BROOKLYN-448:
----------------------------------

             Summary: Support java 8 lambdas as config key values
                 Key: BROOKLYN-448
                 URL: https://issues.apache.org/jira/browse/BROOKLYN-448
             Project: Brooklyn
          Issue Type: Improvement
    Affects Versions: 0.10.0
            Reporter: Aled Sage
            Priority: Minor


It would be nice if users could write Java 8 lambda expressions, and use these 
as config values when writing/using Java-based entities.

However, the persistence (via xstream version 1.4.8) does not work correctly 
for it.

According to http://x-stream.github.io/jira/767/, xstream could not support 
lambdas in 1.4.7 but this was fixed in 1.4.8 (i.e. fixed in the version we 
*are* using). I haven't investigated further as to why it's not serializing as 
we'd expect.

Below is the persisted state file that was written by my test entity. Note the 
"predicate" config value is null.

{noformat}
<entity>
  <brooklynVersion>0.11.0-SNAPSHOT</brooklynVersion>
  <type>org.apache.brooklyn.core.test.entity.TestEntityImpl</type>
  <id>urqjprgoso</id>
  <displayName>TestEntity:urqj</displayName>
  <parent>fy4mk95jwr</parent>
  <config>
    <predicate>
      <null/>
    </predicate>
  </config>
  <attributes>
    <entity.id>urqjprgoso</entity.id>
    <application.id>fy4mk95jwr</application.id>
    <catalog.id>
      <null/>
    </catalog.id>
  </attributes>
  <enrichers>
    <string>sgpovb54t4</string>
    <string>p4blzr6krc</string>
  </enrichers>
  <configKeys>
    <predicate>
      <configKey>
        <name>predicate</name>
        <typeToken class="com.google.common.reflect.TypeToken$SimpleTypeToken">
          <runtimeType 
class="com.google.common.reflect.Types$ParameterizedTypeImpl">
            <argumentsList>
              <com.google.common.reflect.Types_-WildcardTypeImpl>
                <lowerBounds>
                  <java-class>java.lang.String</java-class>
                </lowerBounds>
                <upperBounds>
                  <java-class>java.lang.Object</java-class>
                </upperBounds>
              </com.google.common.reflect.Types_-WildcardTypeImpl>
            </argumentsList>
            <rawType>java.util.function.Predicate</rawType>
          </runtimeType>
        </typeToken>
        <description>predicate</description>
        <reconfigurable>false</reconfigurable>
        <constraint 
class="com.google.common.base.Predicates$ObjectPredicate">ALWAYS_TRUE</constraint>
      </configKey>
    </predicate>
  </configKeys>
</entity>
{noformat}


Below is my Java 8 test to illustrate this: {{testLambdaConfigValue}} fails 
because the retrieved config key value is null after rebind. For comparison, 
the tests {{testAnonymousInnerClassConfigValue}} and 
{{testNonStaticInnerClassConfigValue}} fail at rebind-time with 
{{ConversionException: Could not call java.security.CodeSource.readObject() : 
null}}.

{noformat}
public class LambdaConfigTest extends RebindTestFixtureWithApp {

        @SuppressWarnings("serial")
        public static final ConfigKey<Predicate<? super String>> PREDICATE = 
ConfigKeys.newConfigKey(
                        new TypeToken<Predicate<? super String>>() {},
                        "predicate");

        @Test
        public void testLambdaConfigValue() throws Exception {
                Predicate<? super String> val = p -> p.startsWith("val");
                runPredicateConfigValue(val);
        }

        // Assumes the predicate matches "val1", but not "different1"
        protected void runPredicateConfigValue(Predicate<? super String> val) 
throws Exception {
                Entity entity = 
app().addChild(EntitySpec.create(TestEntity.class)
                                .configure(PREDICATE, val));
                
                List<String> all = ImmutableList.of("val1", "different1");
                List<String> expectedFiltered = ImmutableList.of("val1");
                List<String> filtered = filter(all, 
entity.config().get(PREDICATE));
                assertEquals(filtered, expectedFiltered);
                
                rebind();
                
                Entity newEntity = 
Iterables.getOnlyElement(app().getChildren());
                assertNotNull(newEntity.config().get(PREDICATE));
                List<String> newFiltered = filter(all, 
newEntity.config().get(PREDICATE));
                assertEquals(newFiltered, expectedFiltered);
        }

        private List<String> filter(List<String> vals, Predicate<? super 
String> tester) {
                List<String> result = Lists.newArrayList();
                for (String val : vals) {
                        if (tester.test(val)) {
                                result.add(val);
                        }
                }
                return result;
        }
        
        @Test
        public void testAnonymousInnerClassConfigValue() throws Exception {
                Predicate<? super String> val = new Predicate<String>() {
                        @Override public boolean test(String input) {
                                return input.startsWith("val");
                        }
                };
                runPredicateConfigValue(val);
        }

        @Test
        public void testNonStaticInnerClassConfigValue() throws Exception {
                class MyNontStaticPredicate implements Predicate<String> {
                        @Override public boolean test(String input) {
                                return input.startsWith("val");
                        }
                }
                runPredicateConfigValue(new MyNontStaticPredicate());
        }

        @Test
        public void testStaticInnerClassConfigValue() throws Exception {
                runPredicateConfigValue(new MyStaticPredicate());
        }
        
        static class MyStaticPredicate implements Predicate<String> {
                @Override public boolean test(String input) {
                        return input.startsWith("val");
                }
        }
}
{noformat}




--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

Reply via email to