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)