ModifyFeaturesStrategy extends AbstractThingCommandStrategy<ModifyFeatures> { @Override protected Result<ThingEvent> doApply(final Context<ThingId> context, @Nullable final Thing thing, final long nextRevision, final ModifyFeatures command, @Nullable final Metadata metadata) { final Thing nonNullThing = getEntityOrThrow(thing); final JsonObject thingWithoutFeaturesJsonObject = nonNullThing.removeFeatures().toJson(); final JsonObject featuresJsonObject = command.getFeatures().toJson(); ThingCommandSizeValidator.getInstance().ensureValidSize( () -> { final long lengthWithOutFeatures = thingWithoutFeaturesJsonObject.getUpperBoundForStringSize(); final long featuresLength = featuresJsonObject.getUpperBoundForStringSize() + "features".length() + 5L; return lengthWithOutFeatures + featuresLength; }, () -> { final long lengthWithOutFeatures = thingWithoutFeaturesJsonObject.toString().length(); final long featuresLength = featuresJsonObject.toString().length() + "features".length() + 5L; return lengthWithOutFeatures + featuresLength; }, command::getDittoHeaders); return nonNullThing.getFeatures() .map(features -> getModifyResult(context, nextRevision, command, thing, metadata)) .orElseGet(() -> getCreateResult(context, nextRevision, command, thing, metadata)); } ModifyFeaturesStrategy(); @Override Optional<EntityTag> previousEntityTag(final ModifyFeatures command, @Nullable final Thing previousEntity); @Override Optional<EntityTag> nextEntityTag(final ModifyFeatures command, @Nullable final Thing newEntity);  }
@Test public void modifyFeaturePropertiesSoThatThingGetsTooLarge() { final CommandStrategy.Context<ThingId> context = getDefaultContext(); final Feature feature = Feature.newBuilder() .properties(JsonObject.newBuilder().set("foo", false).set("bar", 42).build()) .withId("myFeature") .build(); final long staticOverhead = 80; final StringBuilder sb = new StringBuilder(); for (int i = 0; i < THING_SIZE_LIMIT_BYTES - staticOverhead; i++) { sb.append('a'); } final JsonObject largeAttributes = JsonObject.newBuilder() .set("a", sb.toString()) .build(); final ThingId thingId = ThingId.of("foo", "bar"); final Thing thing = Thing.newBuilder() .setId(thingId) .setAttributes(largeAttributes) .build(); CreateThing.of(thing, null, DittoHeaders.empty()); final ModifyFeatures command = ModifyFeatures.of(thingId, Features.newBuilder().set(feature).build(), DittoHeaders.empty()); assertThatThrownBy(() -> underTest.doApply(context, thing, NEXT_REVISION, command, null)) .isInstanceOf(ThingTooLargeException.class); }