This is an automated email from the ASF dual-hosted git repository.
heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
The following commit(s) were added to refs/heads/master by this push:
new b3864ca502 add primitive-or-object deserializer, fix bug resolving
entity exprs in triggers
b3864ca502 is described below
commit b3864ca5028800c3e31ad39f2f23e167c9607be2
Author: Alex Heneveld <[email protected]>
AuthorDate: Tue Sep 19 23:46:25 2023 +0100
add primitive-or-object deserializer, fix bug resolving entity exprs in
triggers
---
.../brooklyn/camp/brooklyn/WorkflowYamlTest.java | 58 ++++++--
.../resolve/jackson/AsPropertyIfAmbiguous.java | 4 +-
.../resolve/jackson/CommonTypesSerialization.java | 23 ++-
.../jackson/JsonSymbolDependentDeserializer.java | 3 +-
.../jackson/PrimitiveTokenOrExpectedObject.java | 109 ++++++++++++++
.../core/sensor/AbstractAddTriggerableSensor.java | 43 ++++--
.../BrooklynMiscJacksonSerializationTest.java | 156 +++++++++++++--------
7 files changed, 305 insertions(+), 91 deletions(-)
diff --git
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowYamlTest.java
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowYamlTest.java
index 7519a37b02..fb1b10076c 100644
---
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowYamlTest.java
+++
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/WorkflowYamlTest.java
@@ -18,6 +18,16 @@
*/
package org.apache.brooklyn.camp.brooklyn;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -38,7 +48,13 @@ import org.apache.brooklyn.api.typereg.RegisteredType;
import org.apache.brooklyn.camp.brooklyn.spi.dsl.DslUtils;
import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.BrooklynDslCommon;
import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.entity.*;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.Dumper;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityAdjuncts;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.EntityInternal;
import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
import org.apache.brooklyn.core.entity.trait.Startable;
import org.apache.brooklyn.core.sensor.Sensors;
@@ -48,7 +64,12 @@ import org.apache.brooklyn.core.test.entity.TestEntity;
import org.apache.brooklyn.core.typereg.BasicTypeImplementationPlan;
import org.apache.brooklyn.core.typereg.JavaClassNameTypePlanTransformer;
import org.apache.brooklyn.core.typereg.RegisteredTypes;
-import org.apache.brooklyn.core.workflow.*;
+import org.apache.brooklyn.core.workflow.WorkflowBasicTest;
+import org.apache.brooklyn.core.workflow.WorkflowEffector;
+import org.apache.brooklyn.core.workflow.WorkflowExecutionContext;
+import org.apache.brooklyn.core.workflow.WorkflowPolicy;
+import org.apache.brooklyn.core.workflow.WorkflowStepDefinition;
+import org.apache.brooklyn.core.workflow.WorkflowStepInstanceExecutionContext;
import org.apache.brooklyn.core.workflow.steps.flow.LogWorkflowStep;
import
org.apache.brooklyn.core.workflow.store.WorkflowStatePersistenceViaSensors;
import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
@@ -74,16 +95,6 @@ import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-import java.time.temporal.TemporalUnit;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-
import static
org.apache.brooklyn.util.core.internal.ssh.ExecCmdAsserts.assertExecContains;
import static
org.apache.brooklyn.util.core.internal.ssh.ExecCmdAsserts.assertExecsContain;
import static org.testng.Assert.assertTrue;
@@ -291,6 +302,17 @@ public class WorkflowYamlTest extends AbstractYamlTest {
doTestWorkflowPolicy("condition: { sensor: not_exist }\n" + "period:
200 ms", null);
}
+ @Test
+ public void testWorkflowPolicyTriggersWithEntityId() throws Exception {
+ doTestWorkflowPolicy("triggers: [ { sensor: theTrigger, entity:
other_entity } ]", Duration.seconds(1)::isLongerThan, null, true);
+ }
+ @Test
+ public void testWorkflowPolicyTriggersWithEntityInstance() throws
Exception {
+ // see
org.apache.brooklyn.core.resolve.jackson.BrooklynMiscJacksonSerializationTest.testPrimitiveWithObjectForEntity
+ doTestWorkflowPolicy("triggers: [ { sensor: theTrigger, entity:
$brooklyn:entity(\"other_entity\") } ]", Duration.seconds(1)::isLongerThan,
null, true);
+ }
+
+
static final AttributeSensor<Object> MY_WORKFLOW_SENSOR =
Sensors.newSensor(Object.class, "myWorkflowSensor");
Entity doTestWorkflowSensor(String triggers, Predicate<Duration>
timeCheckOrNullIfShouldFail) throws Exception {
@@ -350,9 +372,13 @@ public class WorkflowYamlTest extends AbstractYamlTest {
}
public void doTestWorkflowPolicy(String triggers, Predicate<Duration>
timeCheckOrNullIfShouldFail, Consumer<Policy> extraChecks) throws Exception {
+ doTestWorkflowPolicy(triggers, timeCheckOrNullIfShouldFail,
extraChecks, false);
+ }
+ public void doTestWorkflowPolicy(String triggers, Predicate<Duration>
timeCheckOrNullIfShouldFail, Consumer<Policy> extraChecks, boolean
useOtherEntity) throws Exception {
Entity app = createAndStartApplication(
"services:",
"- type: " + BasicEntity.class.getName(),
+ " id: main_entity",
" brooklyn.policies:",
" - type: workflow-policy",
" brooklyn.config:",
@@ -370,13 +396,17 @@ public class WorkflowYamlTest extends AbstractYamlTest {
" v: ${v}",
" - transform map x = ${out} | yaml",
" - set-sensor myWorkflowSensor = ${x}",
+ "- type: " + BasicEntity.class.getName(),
+ " id: other_entity",
"");
Stopwatch sw = Stopwatch.createStarted();
waitForApplicationTasks(app);
Duration d1 = Duration.of(sw);
- Entity entity = Iterables.getOnlyElement(app.getChildren());
+ Iterator<Entity> ci = app.getChildren().iterator();
+ Entity entity = ci.next();
+ Entity otherEntity = ci.next();
Policy policy = entity.policies().asList().stream().filter(p -> p
instanceof WorkflowPolicy).findAny().get();
Asserts.assertEquals(policy.getDisplayName(), "Set myWorkflowSensor");
// should really ID be settable from flag?
@@ -390,7 +420,7 @@ public class WorkflowYamlTest extends AbstractYamlTest {
Asserts.assertThat(d2, Duration.millis(500)::isLongerThan);
// EntityAsserts.assertAttributeEqualsEventually(entity, s,
MutableMap.of("foo", "bar", "v", 0));
- entity.sensors().set(Sensors.newStringSensor("theTrigger"), "go");
+ (useOtherEntity ? otherEntity :
entity).sensors().set(Sensors.newStringSensor("theTrigger"), "go");
EntityAsserts.assertAttributeEqualsEventually(MutableMap.of("timeout", "5s"),
entity, MY_WORKFLOW_SENSOR, MutableMap.of("foo", "bar", "v", 0));
// EntityAsserts.assertAttributeEqualsEventually(entity, s,
MutableMap.of("foo", "bar", "v", 1));
Duration d3 = Duration.of(sw).subtract(d2);
diff --git
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/AsPropertyIfAmbiguous.java
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/AsPropertyIfAmbiguous.java
index 6824985ef2..b266cd2b69 100644
---
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/AsPropertyIfAmbiguous.java
+++
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/AsPropertyIfAmbiguous.java
@@ -267,7 +267,9 @@ public class AsPropertyIfAmbiguous {
boolean canTryWithoutType = !typeIdFindResult.isUnambiguous;
try {
Object result = _deserializeTypedForId(p, ctxt, tb,
typeIdFindResult.type);
- if (_idResolver instanceof HasBaseType) {
+ if (result==null) {
+ LOG.trace("Null result deserializing");
+ } else if (_idResolver instanceof HasBaseType) {
JavaType baseType = ((HasBaseType)
_idResolver).getBaseType();
if (baseType != null) {
Class<?> rawClass = baseType.getRawClass();
diff --git
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/CommonTypesSerialization.java
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/CommonTypesSerialization.java
index fb5e553bec..f294ee80f8 100644
---
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/CommonTypesSerialization.java
+++
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/CommonTypesSerialization.java
@@ -31,15 +31,21 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.google.common.reflect.TypeToken;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.EntityManager;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.api.objs.BrooklynObject;
import org.apache.brooklyn.api.objs.BrooklynObjectType;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
+import org.apache.brooklyn.core.mgmt.internal.EntityManagerInternal;
+import org.apache.brooklyn.core.mgmt.internal.NonDeploymentManagementContext;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.core.flags.BrooklynTypeNameResolution;
import org.apache.brooklyn.util.core.flags.FlagUtils;
import org.apache.brooklyn.util.core.predicates.DslPredicates;
+import org.apache.brooklyn.util.core.task.Tasks;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.javalang.Boxing;
import org.apache.brooklyn.util.time.Duration;
@@ -356,6 +362,17 @@ public class CommonTypesSerialization {
// we could support 'current' to use tasks to resolve, which might
be handy
BrooklynObject result = mgmt.lookup(value);
if (result!=null) return result;
+
+ Entity currentEntity =
BrooklynTaskTags.getContextEntity(Tasks.current());
+ if (currentEntity!=null) {
+ // during initialization, we can look relative to ourselves,
since entities aren't available in mgmt.lookup
+ Iterable<Entity> ents = ((EntityManagerInternal)
mgmt.getEntityManager()).getAllEntitiesInApplication(currentEntity.getApplication());
+ for (Entity e : ents) {
+ if (Objects.equals(value, e.getId())) {
+ return e;
+ }
+ }
+ }
throw new IllegalStateException("Entity or other BrooklynObject
'"+value+"' is not known here");
}
@@ -443,7 +460,11 @@ public class CommonTypesSerialization {
return super.convertStringToObject(value, p, ctxt);
} catch (Exception e) {
Exceptions.propagateIfFatal(e);
- LOG.warn("Reference to BrooklynObject "+value+" which is
unknown or no longer available; replacing with 'null'");
+ if (BrooklynObjectSerialization.this.mgmt instanceof
NonDeploymentManagementContext) {
+ LOG.warn("Reference to BrooklynObject " + value + "
which is unknown or not yet known, using NonDeployment context; replacing with
'null': "+e);
+ } else {
+ LOG.warn("Reference to BrooklynObject " + value + "
which is unknown or no longer available; replacing with 'null': "+e);
+ }
return null;
}
}
diff --git
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/JsonSymbolDependentDeserializer.java
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/JsonSymbolDependentDeserializer.java
index 93d8b7f9d1..5b2c5fff2e 100644
---
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/JsonSymbolDependentDeserializer.java
+++
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/JsonSymbolDependentDeserializer.java
@@ -29,6 +29,8 @@ import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.util.Set;
import java.util.function.Function;
+
+import org.apache.brooklyn.util.core.units.Range;
import org.apache.brooklyn.util.core.xstream.ImmutableSetConverter;
import static
org.apache.brooklyn.core.resolve.jackson.BrooklynJacksonSerializationUtils.createBeanDeserializer;
@@ -152,5 +154,4 @@ public abstract class JsonSymbolDependentDeserializer
extends JsonDeserializer<O
/** try to do low level build so we don't recreate ourselves
and loop endlessly */ true,
true);
}
-
}
diff --git
a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/PrimitiveTokenOrExpectedObject.java
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/PrimitiveTokenOrExpectedObject.java
new file mode 100644
index 0000000000..ff342c29a5
--- /dev/null
+++
b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/PrimitiveTokenOrExpectedObject.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.resolve.jackson;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.BeanProperty;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import
org.apache.brooklyn.core.resolve.jackson.PrimitiveTokenOrExpectedObject.PrimitiveTokenOrExpectedObjectDeserializer;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
+
+import static
org.apache.brooklyn.core.resolve.jackson.BrooklynJacksonSerializationUtils.createBeanDeserializer;
+
+/**
+ * This is an object intended for use in Jackson setters. When supplied with a
primitive token, the value is stored as the primitive.
+ * For anything else, it is deserialized according to the type T.
+ * Thus setters can inspect the object and call the right method, and a custom
string can be handled specially without need for lower-level Jackson
interrogation,
+ * but if the object, or a map of the object is supplied, it is used.
+ */
+@JsonDeserialize(using = PrimitiveTokenOrExpectedObjectDeserializer.class)
+public class PrimitiveTokenOrExpectedObject<T> {
+
+ // exactly one of these will be set
+ public T object;
+ public Object primitive;
+
+ public boolean hasObject() { return object!=null; }
+ public boolean hasPrimitive() { return primitive!=null; }
+ public boolean hasStringPrimitive() { return primitive instanceof String; }
+
+ public T asObject() { return object; }
+ public Object asPrimitive() { return primitive; }
+ public String asString() { if (hasStringPrimitive()) return
(String)primitive; return null; }
+
+ public static class PrimitiveTokenOrExpectedObjectDeserializer extends
JsonSymbolDependentDeserializer {
+ public PrimitiveTokenOrExpectedObjectDeserializer() {
+ super();
+ }
+ @Override
+ public JavaType getDefaultType() {
+ return ctxt.constructType(Object.class);
+ }
+
+ protected Maybe<Object> getTokenValue(JsonToken token, JsonParser p) {
+ try {
+ if (SIMPLE_TOKENS.contains(token)) {
+ if (JsonToken.VALUE_STRING.equals(token)) return
Maybe.of(p.getValueAsString());
+ if (JsonToken.VALUE_NUMBER_INT.equals(token)) return
Maybe.of(p.getValueAsInt());
+ if (JsonToken.VALUE_NUMBER_FLOAT.equals(token)) return
Maybe.of(p.getValueAsDouble());
+ if (token.isBoolean()) return
Maybe.of(p.getValueAsBoolean());
+ if (JsonToken.VALUE_NULL.equals(token)) return
Maybe.ofAllowingNull(null);
+ }
+ return Maybe.absent();
+ } catch (IOException e) {
+ throw Exceptions.propagate(e);
+ }
+ }
+ @Override
+ protected Object deserializeToken(JsonParser p) throws IOException {
+ PrimitiveTokenOrExpectedObject result = new
PrimitiveTokenOrExpectedObject();
+ result.primitive = getTokenValue(p.getCurrentToken(), p).get();
+ return result;
+ }
+
+ @Override
+ protected Object deserializeObject(JsonParser p) throws IOException {
+ PrimitiveTokenOrExpectedObject result = new
PrimitiveTokenOrExpectedObject();
+ result.object = super.deserializeObject(p);
+ return result;
+ }
+
+ protected JsonDeserializer<?> getObjectDeserializer() throws
IOException, JsonProcessingException {
+ if (type!=null &&
PrimitiveTokenOrExpectedObject.class.equals(type.getRawClass())) {
+ // this should always happen
+ return ctxt.findRootValueDeserializer(type.containedType(0));
+ } else {
+ return super.getObjectDeserializer();
+ }
+ }
+
+ public JsonDeserializer<?> createContextual(DeserializationContext
ctxt, BeanProperty property) throws JsonMappingException {
+ return super.createContextual(ctxt, property);
+ }
+ }
+}
diff --git
a/core/src/main/java/org/apache/brooklyn/core/sensor/AbstractAddTriggerableSensor.java
b/core/src/main/java/org/apache/brooklyn/core/sensor/AbstractAddTriggerableSensor.java
index f9adc8aae7..a5c2c5a241 100644
---
a/core/src/main/java/org/apache/brooklyn/core/sensor/AbstractAddTriggerableSensor.java
+++
b/core/src/main/java/org/apache/brooklyn/core/sensor/AbstractAddTriggerableSensor.java
@@ -26,6 +26,7 @@ import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonSetter;
import com.google.common.annotations.Beta;
import com.google.common.base.Predicates;
import com.google.common.reflect.TypeToken;
@@ -38,6 +39,7 @@ import org.apache.brooklyn.core.entity.EntityInitializers;
import org.apache.brooklyn.core.entity.EntityPredicates;
import org.apache.brooklyn.core.feed.PollConfig;
import org.apache.brooklyn.core.mgmt.internal.AppGroupTraverser;
+import org.apache.brooklyn.core.resolve.jackson.PrimitiveTokenOrExpectedObject;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.predicates.DslPredicates;
@@ -105,26 +107,28 @@ public abstract class AbstractAddTriggerableSensor<T>
extends AbstractAddSensorF
t = new SensorFeedTrigger();
t.sensorName = (String) ti;
} else {
- throw new IllegalStateException("Trigger should be a map
specifyin entity and sensor");
+ throw new IllegalStateException("Trigger should be a map
specifying entity and sensor");
}
}
Entity entity = t.entity;
- if (entity==null && t.entityId!=null) {
- String desiredComponentId = t.entityId;
- List<Entity> firstGroupOfMatches =
AppGroupTraverser.findFirstGroupOfMatches(context, true,
-
Predicates.and(EntityPredicates.configEqualTo(BrooklynConfigKeys.PLAN_ID,
desiredComponentId), x->true)::apply);
- if (firstGroupOfMatches.isEmpty()) {
- firstGroupOfMatches =
AppGroupTraverser.findFirstGroupOfMatches(context, true,
-
Predicates.and(EntityPredicates.idEqualTo(desiredComponentId), x->true)::apply);
- }
- if (!firstGroupOfMatches.isEmpty()) {
- entity = firstGroupOfMatches.get(0);
+ if (entity==null) {
+ if (t.entityId != null) {
+ String desiredComponentId = t.entityId;
+ List<Entity> firstGroupOfMatches =
AppGroupTraverser.findFirstGroupOfMatches(context, true,
+
Predicates.and(EntityPredicates.configEqualTo(BrooklynConfigKeys.PLAN_ID,
desiredComponentId), x -> true)::apply);
+ if (firstGroupOfMatches.isEmpty()) {
+ firstGroupOfMatches =
AppGroupTraverser.findFirstGroupOfMatches(context, true,
+
Predicates.and(EntityPredicates.idEqualTo(desiredComponentId), x ->
true)::apply);
+ }
+ if (!firstGroupOfMatches.isEmpty()) {
+ entity = firstGroupOfMatches.get(0);
+ } else {
+ throw new IllegalStateException("Cannot find entity
with ID '" + desiredComponentId + "'");
+ }
} else {
- throw new IllegalStateException("Cannot find entity with
ID '"+desiredComponentId+"'");
+ entity = context;
}
- } else {
- entity = context;
}
Sensor sensor = t.sensor;
@@ -157,6 +161,17 @@ public abstract class AbstractAddTriggerableSensor<T>
extends AbstractAddSensorF
// could support predicates on the value; but we do it on the entity
which is enough
+ @JsonSetter
+// @JsonDeserialize(using = PrimitiveOrObjectDeserializer.class)
+// @JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
+ public void setEntity(PrimitiveTokenOrExpectedObject<Entity> po) {
+ //@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
@JsonDeserialize(using = PrimitiveOrObjectDeserializer.class)
+// Object entity) {
+ if (po.hasObject()) setEntity(po.asObject());
+ else if (po.hasStringPrimitive()) setEntity(po.asString());
+ else if (entity==null) { /* do nothing */ }
+ else throw new IllegalArgumentException("Invalid input for entity
to "+this+": "+entity);
+ }
public void setEntity(Entity entity) {
this.entity = entity;
}
diff --git
a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
index 4e74a964ee..fb38bb9ecb 100644
---
a/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
+++
b/core/src/test/java/org/apache/brooklyn/core/resolve/jackson/BrooklynMiscJacksonSerializationTest.java
@@ -18,6 +18,15 @@
*/
package org.apache.brooklyn.core.resolve.jackson;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.function.BiConsumer;
+
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -28,8 +37,12 @@ import
com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.util.TokenBuffer;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import com.google.common.reflect.TypeToken;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.mgmt.ManagementContext;
+import
org.apache.brooklyn.core.sensor.AbstractAddTriggerableSensor.SensorFeedTrigger;
import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.apache.brooklyn.entity.stock.BasicApplicationImpl;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
@@ -47,11 +60,6 @@ import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import java.io.IOException;
-import java.time.Instant;
-import java.util.*;
-import java.util.function.BiConsumer;
-
public class BrooklynMiscJacksonSerializationTest implements MapperTestFixture
{
private static final Logger LOG =
LoggerFactory.getLogger(BrooklynMiscJacksonSerializationTest.class);
@@ -59,7 +67,7 @@ public class BrooklynMiscJacksonSerializationTest implements
MapperTestFixture {
private ObjectMapper mapper;
public ObjectMapper mapper() {
- if (mapper==null) mapper = BeanWithTypeUtils.newMapper(null, false,
null, true);
+ if (mapper == null) mapper = BeanWithTypeUtils.newMapper(null, false,
null, true);
return mapper;
}
@@ -70,12 +78,13 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
// baseline
- static class EmptyObject {}
+ static class EmptyObject {
+ }
@Test
public void testMapperDoesntBreakBasicThings() throws Exception {
Asserts.assertEquals(deser("\"hello\""), "hello");
-
Asserts.assertInstanceOf(deser("{\"type\":\""+EmptyObject.class.getName()+"\"}"),
EmptyObject.class);
+ Asserts.assertInstanceOf(deser("{\"type\":\"" +
EmptyObject.class.getName() + "\"}"), EmptyObject.class);
}
@Test
@@ -90,7 +99,7 @@ public class BrooklynMiscJacksonSerializationTest implements
MapperTestFixture {
public String toString() {
return "Obj{" +
"foo='" + foo + '\'' +
- "}@"+ System.identityHashCode(this);
+ "}@" + System.identityHashCode(this);
}
}
@@ -100,37 +109,42 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
mapper = BeanWithTypeUtils.applyCommonMapperConfig(mapper, null,
false, null, true);
mapper = new
ObjectReferencingSerialization().useAndApplytoMapper(mapper);
- ObjForSerializingAsReference f1 = new ObjForSerializingAsReference();
f1.foo = "1";
- ObjForSerializingAsReference f2 = new ObjForSerializingAsReference();
f2.foo = "2";
+ ObjForSerializingAsReference f1 = new ObjForSerializingAsReference();
+ f1.foo = "1";
+ ObjForSerializingAsReference f2 = new ObjForSerializingAsReference();
+ f2.foo = "2";
String out = ser(MutableMap.of("a", f1, "b", f2, "c", f1));
- LOG.info("Result of "+ JavaClassNames.niceClassAndMethod()+": "+out);
+ LOG.info("Result of " + JavaClassNames.niceClassAndMethod() + ": " +
out);
Map in = deser(out,
Map.class
// new TypeToken<Map<String, ObjForSerializingAsReference>>() {}
);
- ObjForSerializingAsReference a =
(ObjForSerializingAsReference)in.get("a");
- ObjForSerializingAsReference b =
(ObjForSerializingAsReference)in.get("b");
- ObjForSerializingAsReference c =
(ObjForSerializingAsReference)in.get("c");
- Asserts.assertTrue(a.foo.equals(c.foo), "expected same foo value for a
and c - "+a+" != "+c);
+ ObjForSerializingAsReference a = (ObjForSerializingAsReference)
in.get("a");
+ ObjForSerializingAsReference b = (ObjForSerializingAsReference)
in.get("b");
+ ObjForSerializingAsReference c = (ObjForSerializingAsReference)
in.get("c");
+ Asserts.assertTrue(a.foo.equals(c.foo), "expected same foo value for a
and c - " + a + " != " + c);
Asserts.assertTrue(!b.foo.equals(c.foo), "expected different foo value
for a and b");
- Asserts.assertTrue(a == c, "expected same instance for a and c - "+a+"
!= "+c);
+ Asserts.assertTrue(a == c, "expected same instance for a and c - " + a
+ " != " + c);
Asserts.assertTrue(a != b, "expected different instance for a and b");
}
@Test
public void testObjectReferences() throws IOException {
- ObjForSerializingAsReference f1 = new ObjForSerializingAsReference();
f1.foo = "1";
+ ObjForSerializingAsReference f1 = new ObjForSerializingAsReference();
+ f1.foo = "1";
Object f2 = new
ObjectReferencingSerialization().serializeAndDeserialize(f1);
Asserts.assertEquals(f1, f2);
- Asserts.assertTrue(f1==f2, "different instances for "+f1+" and "+f2);
+ Asserts.assertTrue(f1 == f2, "different instances for " + f1 + " and "
+ f2);
}
public static class ObjRefAcceptingStringSource {
String src;
ObjRefAcceptingStringSource bar;
- public ObjRefAcceptingStringSource() {}
+ public ObjRefAcceptingStringSource() {
+ }
+
public ObjRefAcceptingStringSource(String src) {
this.src = src;
}
@@ -141,16 +155,16 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
ManagementContext mgmt = LocalManagementContextForTests.newInstance();
Asserts.assertFailsWith(() -> {
- ObjRefAcceptingStringSource b =
BeanWithTypeUtils.convertShallow(mgmt, MutableMap.of("bar", new
DeferredSupplier() {
- @Override
- public Object get() {
- return "xxx";
- }
- }), TypeToken.of(ObjRefAcceptingStringSource.class), false,
null, true);
- // ensure the ID of a serialized object isn't treated as a
reference
- Asserts.fail("Should have failed, instead got: " + b.bar.src);
- return b;
- }, e -> Asserts.expectedFailureContains(e, "Problem deserializing
property 'bar'"));
+ ObjRefAcceptingStringSource b =
BeanWithTypeUtils.convertShallow(mgmt, MutableMap.of("bar", new
DeferredSupplier() {
+ @Override
+ public Object get() {
+ return "xxx";
+ }
+ }), TypeToken.of(ObjRefAcceptingStringSource.class), false, null,
true);
+ // ensure the ID of a serialized object isn't treated as a
reference
+ Asserts.fail("Should have failed, instead got: " + b.bar.src);
+ return b;
+ }, e -> Asserts.expectedFailureContains(e, "Problem deserializing
property 'bar'"));
ObjRefAcceptingStringSource b = BeanWithTypeUtils.convertShallow(mgmt,
MutableMap.of("bar", new ObjRefAcceptingStringSource("good")),
TypeToken.of(ObjRefAcceptingStringSource.class), false, null, true);
Asserts.assertEquals(b.bar.src, "good");
@@ -185,7 +199,7 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
public static class DateTimeBean {
String x;
Date juDate;
-// LocalDateTime localDateTime;
+ // LocalDateTime localDateTime;
GregorianCalendar calendar;
Instant instant;
}
@@ -196,11 +210,11 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
// mapper.findAndRegisterModules();
DateTimeBean impl = new DateTimeBean();
- Asserts.assertEquals(ser(impl, DateTimeBean.class), "{}" );
+ Asserts.assertEquals(ser(impl, DateTimeBean.class), "{}");
impl.x = "foo";
- impl.juDate = new Date(60*1000);
+ impl.juDate = new Date(60 * 1000);
// impl.localDateTime = LocalDateTime.of(2020, 1, 1, 12, 0, 0, 0);
impl.calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"),
Locale.ROOT);
impl.calendar.set(2020, 0, 1, 12, 0, 0);
@@ -222,18 +236,18 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
"instant: 2020-01-01T12:00:00Z",
""
), DateTimeBean.class);
- Assert.assertEquals( impl2.x, impl.x );
- Assert.assertEquals( impl2.juDate, impl.juDate );
+ Assert.assertEquals(impl2.x, impl.x);
+ Assert.assertEquals(impl2.juDate, impl.juDate);
// Assert.assertEquals( impl2.localDateTime, impl.localDateTime );
// Assert.assertEquals( impl2.calendar, impl.calendar );
- Assert.assertEquals( impl2.instant, impl.instant );
+ Assert.assertEquals(impl2.instant, impl.instant);
}
@Test
public void testInstantConversionFromVarious() throws Exception {
mapper = BeanWithTypeUtils.newYamlMapper(null, false, null, true);
long utc = new Date().getTime();
- Instant inst = mapper.readerFor(Instant.class).readValue(
mapper.writeValueAsString(utc) );
+ Instant inst =
mapper.readerFor(Instant.class).readValue(mapper.writeValueAsString(utc));
// below known not to work, as long is converted to ["j...Long", utc]
which we don't process
//mapper.readerFor(Instant.class).readValue(
mapper.writerFor(Object.class).writeValueAsString(utc) );
@@ -242,8 +256,8 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
BeanWithTypeUtils.convertShallow(mgmt, utc,
TypeToken.of(Instant.class), false, null, false);
BeanWithTypeUtils.convertDeeply(mgmt, utc,
TypeToken.of(Instant.class), false, null, false);
- BeanWithTypeUtils.convertShallow(mgmt, ""+utc,
TypeToken.of(Instant.class), false, null, false);
- BeanWithTypeUtils.convertDeeply(mgmt, ""+utc,
TypeToken.of(Instant.class), false, null, false);
+ BeanWithTypeUtils.convertShallow(mgmt, "" + utc,
TypeToken.of(Instant.class), false, null, false);
+ BeanWithTypeUtils.convertDeeply(mgmt, "" + utc,
TypeToken.of(Instant.class), false, null, false);
BeanWithTypeUtils.convertShallow(mgmt, inst,
TypeToken.of(Instant.class), false, null, false);
BeanWithTypeUtils.convertDeeply(mgmt, inst,
TypeToken.of(Instant.class), false, null, false);
@@ -270,7 +284,7 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
public void testStringBean() throws Exception {
Duration d = mapper().readValue("\"1m\"", Duration.class);
Asserts.assertEquals(d, Duration.ONE_MINUTE);
- Object d0 =
mapper().readValue("{\"type\":\""+Duration.class.getName()+"\",\"value\":\"1s\"}",
Object.class);
+ Object d0 = mapper().readValue("{\"type\":\"" +
Duration.class.getName() + "\",\"value\":\"1s\"}", Object.class);
Asserts.assertEquals(d0, Duration.ONE_SECOND);
}
@@ -282,7 +296,7 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
@Test
public void testJsonPassThrough() throws Exception {
- BiConsumer<String,Object> check = (input, expected) -> {
+ BiConsumer<String, Object> check = (input, expected) -> {
try {
JsonPassThroughDeserializer.JsonObjectHolder x =
mapper().readValue(input, JsonPassThroughDeserializer.JsonObjectHolder.class);
Asserts.assertEquals(x.value, expected);
@@ -297,7 +311,7 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
check.accept("42", 42);
check.accept("{\"k\":\"v\"}", MutableMap.of("k", "v"));
check.accept("[\"a\",1]", MutableList.of("a", 1));
-
check.accept("[\"a\",{\"type\":\""+Duration.class.getName()+"\",\"value\":\"1s\"}]",
+ check.accept("[\"a\",{\"type\":\"" + Duration.class.getName() +
"\",\"value\":\"1s\"}]",
MutableList.of("a", MutableMap.of("type",
Duration.class.getName(), "value", "1s")));
}
@@ -311,11 +325,17 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
public Object subtypeWanted;
public String x;
}
+
@JsonDeserialize(using = JsonDeserializer.None.class)
- static class SampleFromStringSubtype extends SampleFromStringDeserialized
{}
+ static class SampleFromStringSubtype extends SampleFromStringDeserialized {
+ }
+
@JsonDeserialize(using = JsonDeserializer.None.class)
- static class SampleFromStringSubtype1 extends SampleFromStringSubtype {}
- static class SampleFromStringSubtype2 extends SampleFromStringSubtype {}
+ static class SampleFromStringSubtype1 extends SampleFromStringSubtype {
+ }
+
+ static class SampleFromStringSubtype2 extends SampleFromStringSubtype {
+ }
static class SampleFromStringDeserializer extends JsonDeserializer {
@Override
@@ -326,13 +346,13 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
ctxt);
Integer rawi = null;
- if (raw instanceof String) rawi = Integer.parseInt((String)raw);
- if (raw instanceof Integer) rawi = (Integer)raw;
- if (rawi!=null) {
+ if (raw instanceof String) rawi = Integer.parseInt((String) raw);
+ if (raw instanceof Integer) rawi = (Integer) raw;
+ if (rawi != null) {
SampleFromStringSubtype result = null;
- if (rawi==1) result = new SampleFromStringSubtype1();
- if (rawi==2) result = new SampleFromStringSubtype2();
- if (result!=null) {
+ if (rawi == 1) result = new SampleFromStringSubtype1();
+ if (rawi == 2) result = new SampleFromStringSubtype2();
+ if (result != null) {
result.subtypeWanted = raw;
}
return result;
@@ -340,9 +360,9 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
if (raw instanceof Map) {
Integer stw = TypeCoercions.tryCoerce(((Map)
raw).get("subtypeWanted"), Integer.class).orNull();
- if (stw!=null && stw>=0) {
+ if (stw != null && stw >= 0) {
try {
- return
ctxt.findNonContextualValueDeserializer(ctxt.constructType(Class.forName(SampleFromStringSubtype.class.getName()+stw))).deserialize(
+ return
ctxt.findNonContextualValueDeserializer(ctxt.constructType(Class.forName(SampleFromStringSubtype.class.getName()
+ stw))).deserialize(
BrooklynJacksonSerializationUtils.createParserFromTokenBufferAndParser(buffer,
p), ctxt);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
@@ -361,25 +381,41 @@ public class BrooklynMiscJacksonSerializationTest
implements MapperTestFixture {
mapper = BeanWithTypeUtils.newSimpleYamlMapper();
//YAMLMapper.builder().build();
s =
mapper.readerFor(SampleFromStringDeserialized.class).readValue("1");
Asserts.assertInstanceOf(s, SampleFromStringSubtype1.class);
- Asserts.assertEquals( ((SampleFromStringSubtype)s).subtypeWanted, 1 );
+ Asserts.assertEquals(((SampleFromStringSubtype) s).subtypeWanted, 1);
s =
mapper.readerFor(SampleFromStringDeserialized.class).readValue("\"2\"");
Asserts.assertInstanceOf(s, SampleFromStringSubtype2.class);
- Asserts.assertEquals( ((SampleFromStringSubtype)s).subtypeWanted, "2"
);
+ Asserts.assertEquals(((SampleFromStringSubtype) s).subtypeWanted, "2");
s =
mapper.readerFor(SampleFromStringDeserialized.class).readValue("subtypeWanted:
1");
Asserts.assertInstanceOf(s, SampleFromStringSubtype1.class);
- Asserts.assertEquals( ((SampleFromStringSubtype)s).subtypeWanted, 1 );
+ Asserts.assertEquals(((SampleFromStringSubtype) s).subtypeWanted, 1);
s =
mapper.readerFor(SampleFromStringDeserialized.class).readValue("subtypeWanted:
\"-1\"");
Asserts.assertEquals(s.getClass(), SampleFromStringSubtype.class);
- Asserts.assertEquals( ((SampleFromStringSubtype)s).subtypeWanted, "-1"
);
+ Asserts.assertEquals(((SampleFromStringSubtype) s).subtypeWanted,
"-1");
s = TypeCoercions.coerce("1", SampleFromStringDeserialized.class);
Asserts.assertInstanceOf(s, SampleFromStringSubtype1.class);
- Asserts.assertEquals( ((SampleFromStringSubtype)s).subtypeWanted, "1"
);
+ Asserts.assertEquals(((SampleFromStringSubtype) s).subtypeWanted, "1");
s = TypeCoercions.coerce(1, SampleFromStringDeserialized.class);
- Asserts.assertEquals( ((SampleFromStringSubtype)s).subtypeWanted, 1 );
+ Asserts.assertEquals(((SampleFromStringSubtype) s).subtypeWanted, 1);
+ }
+
+ @Test
+ public void testPrimitiveWithObjectForEntity() throws Exception {
+ ManagementContext mgmt = LocalManagementContextForTests.newInstance();
+ Entity app =
mgmt.getEntityManager().createEntity(EntitySpec.create(BasicApplicationImpl.class));
+
+ Asserts.assertThat(BeanWithTypeUtils.convert(mgmt,
+ MutableMap.of("entity", app, "sensor", "aTrigger"),
+ TypeToken.of(SensorFeedTrigger.class), true, null,
true),
+ f -> f != null && app.equals(f.getEntity()) &&
f.getSensor().equals("aTrigger"));
+
+ Asserts.assertThat(BeanWithTypeUtils.convert(mgmt,
+ MutableMap.of("entity", app.getApplicationId(),
"sensor", "aTrigger"),
+ TypeToken.of(SensorFeedTrigger.class), true, null,
true),
+ f -> f != null && app.getId().equals(f.getEntity()) &&
f.getSensor().equals("aTrigger"));
}
-}
+}
\ No newline at end of file