From 87c2e8973a59c91e8854a167ee2e728f05afefcb Mon Sep 17 00:00:00 2001 From: Eduardo Pinto Date: Thu, 4 Jan 2024 13:51:26 +0000 Subject: [PATCH] chore: validate components are public --- .../kalix/javasdk/impl/Validations.scala | 12 +++ .../javasdk/impl/NotPublicComponents.java | 86 +++++++++++++++++++ .../impl/ActionDescriptorFactorySpec.scala | 7 ++ ...ntSourcedEntityDescriptorFactorySpec.scala | 7 ++ .../ValueEntityDescriptorFactorySpec.scala | 6 ++ .../impl/ViewDescriptorFactorySpec.scala | 6 ++ .../WorkflowEntityDescriptorFactorySpec.scala | 6 ++ 7 files changed, 130 insertions(+) create mode 100644 sdk/java-sdk-spring/src/test/java/kalix/javasdk/impl/NotPublicComponents.java diff --git a/sdk/java-sdk-spring/src/main/scala/kalix/javasdk/impl/Validations.scala b/sdk/java-sdk-spring/src/main/scala/kalix/javasdk/impl/Validations.scala index 39aa748dc3..31918fe1e4 100644 --- a/sdk/java-sdk-spring/src/main/scala/kalix/javasdk/impl/Validations.scala +++ b/sdk/java-sdk-spring/src/main/scala/kalix/javasdk/impl/Validations.scala @@ -142,12 +142,24 @@ object Validations { } def validate(component: Class[_]): Validation = + componentMustBePublic(component) ++ validateAction(component) ++ validateView(component) ++ validateValueEntity(component) ++ validateEventSourcedEntity(component) ++ validateWorkflow(component) + private def componentMustBePublic(component: Class[_]): Validation = { + if (component.isPublic) { + Valid + } else { + Invalid( + errorMessage( + component, + s"${component.getSimpleName} is not marked with `public` modifier. Components must be public.")) + } + } + private def validateCompoundIdsOrder(component: Class[_]): Validation = { val restService = RestServiceIntrospector.inspectService(component) component.getMethods.toIndexedSeq diff --git a/sdk/java-sdk-spring/src/test/java/kalix/javasdk/impl/NotPublicComponents.java b/sdk/java-sdk-spring/src/test/java/kalix/javasdk/impl/NotPublicComponents.java new file mode 100644 index 0000000000..9876065655 --- /dev/null +++ b/sdk/java-sdk-spring/src/test/java/kalix/javasdk/impl/NotPublicComponents.java @@ -0,0 +1,86 @@ +/* + * Copyright 2021 Lightbend Inc. + * + * Licensed 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 kalix.javasdk.impl; + +import kalix.javasdk.action.Action; +import kalix.javasdk.annotations.*; +import kalix.javasdk.eventsourcedentity.EventSourcedEntity; +import kalix.javasdk.valueentity.ValueEntity; +import kalix.javasdk.view.View; +import kalix.javasdk.workflow.Workflow; +import kalix.spring.testmodels.Message; +import kalix.spring.testmodels.valueentity.User; +import kalix.spring.testmodels.valueentity.UserEntity; +import kalix.spring.testmodels.workflow.StartWorkflow; +import kalix.spring.testmodels.workflow.WorkflowState; +import org.springframework.web.bind.annotation.*; + +// below components are not public and thus need to be in the same package as the corresponding test +public class NotPublicComponents { + static class NotPublicAction extends Action { + @GetMapping("/message") + public Action.Effect message() { + return effects().ignore(); + } + } + + @Id("counter_id") + @TypeId("counter") + static class NotPublicEventSourced extends EventSourcedEntity { + @GetMapping("/eventsourced/{counter_id}") + public Integer test() { + return 0; + } + } + + @Id("id") + @TypeId("user") + @RequestMapping("/user/{id}") + static class NotPublicValueEntity extends ValueEntity { + + @GetMapping + public ValueEntity.Effect ok() { + return effects().reply("ok"); + } + } + + @Table(value = "users_view") + @Subscribe.ValueEntity(UserEntity.class) + static class NotPublicView extends View { + @Query("SELECT * FROM users_view WHERE email = :email") + @GetMapping("/users/{email}") + public User getUser(@PathVariable String email) { + return null; + } + } + + @TypeId("transfer-workflow") + @Id("transferId") + @RequestMapping("/transfer/{transferId}") + static class NotPublicWorkflow extends Workflow { + @Override + public WorkflowDef definition() { + return null; + } + + @PutMapping + public Effect startTransfer(@RequestBody StartWorkflow startWorkflow) { + return null; + } + } +} + diff --git a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ActionDescriptorFactorySpec.scala b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ActionDescriptorFactorySpec.scala index 1896dd601a..061a8bf831 100644 --- a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ActionDescriptorFactorySpec.scala +++ b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ActionDescriptorFactorySpec.scala @@ -108,8 +108,15 @@ import scala.jdk.CollectionConverters.CollectionHasAsScala class ActionDescriptorFactorySpec extends AnyWordSpec with ComponentDescriptorSuite { + // missing public modifier "Action descriptor factory" should { + "validate an Action must be declared as public" in { + intercept[InvalidComponentException] { + Validations.validate(classOf[NotPublicComponents.NotPublicAction]).failIfInvalid + }.getMessage should include("NotPublicAction is not marked with `public` modifier. Components must be public.") + } + "generate mappings for an Action with GET without path param" in { assertDescriptor[GetWithoutParam] { desc => diff --git a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/EventSourcedEntityDescriptorFactorySpec.scala b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/EventSourcedEntityDescriptorFactorySpec.scala index ccb75c1870..406854caa5 100644 --- a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/EventSourcedEntityDescriptorFactorySpec.scala +++ b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/EventSourcedEntityDescriptorFactorySpec.scala @@ -39,6 +39,13 @@ import scala.jdk.CollectionConverters.CollectionHasAsScala class EventSourcedEntityDescriptorFactorySpec extends AnyWordSpec with ComponentDescriptorSuite { "EventSourced descriptor factory" should { + + "validate an ESE must be declared as public" in { + intercept[InvalidComponentException] { + Validations.validate(classOf[NotPublicComponents.NotPublicEventSourced]).failIfInvalid + }.getMessage should include("NotPublicEventSourced is not marked with `public` modifier. Components must be public.") + } + "generate mappings for a Event Sourced with entity ids in path" in { assertDescriptor[CounterEventSourcedEntity] { desc => val method = desc.commandHandlers("GetInteger") diff --git a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ValueEntityDescriptorFactorySpec.scala b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ValueEntityDescriptorFactorySpec.scala index ce8fb8a9c2..6d0dfdb22d 100644 --- a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ValueEntityDescriptorFactorySpec.scala +++ b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ValueEntityDescriptorFactorySpec.scala @@ -37,6 +37,12 @@ import scala.jdk.CollectionConverters.CollectionHasAsScala class ValueEntityDescriptorFactorySpec extends AnyWordSpec with ComponentDescriptorSuite { "ValueEntity descriptor factory" should { + "validate a ValueEntity must be declared as public" in { + intercept[InvalidComponentException] { + Validations.validate(classOf[NotPublicComponents.NotPublicValueEntity]).failIfInvalid + }.getMessage should include("NotPublicValueEntity is not marked with `public` modifier. Components must be public.") + } + "generate mappings for a Value Entity with entity ids in path" in { assertDescriptor[PostWithIds] { desc => val method = desc.commandHandlers("CreateEntity") diff --git a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ViewDescriptorFactorySpec.scala b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ViewDescriptorFactorySpec.scala index 533c348e9f..b22e6a2239 100644 --- a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ViewDescriptorFactorySpec.scala +++ b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/ViewDescriptorFactorySpec.scala @@ -72,6 +72,12 @@ class ViewDescriptorFactorySpec extends AnyWordSpec with ComponentDescriptorSuit "View descriptor factory" should { + "validate a View must be declared as public" in { + intercept[InvalidComponentException] { + Validations.validate(classOf[NotPublicComponents.NotPublicView]).failIfInvalid + }.getMessage should include("NotPublicView is not marked with `public` modifier. Components must be public.") + } + "generate ACL annotations at service level" in { assertDescriptor[ViewWithServiceLevelAcl] { desc => val extension = desc.serviceDescriptor.getOptions.getExtension(kalix.Annotations.service) diff --git a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/WorkflowEntityDescriptorFactorySpec.scala b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/WorkflowEntityDescriptorFactorySpec.scala index feb77a241a..890a1c1a16 100644 --- a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/WorkflowEntityDescriptorFactorySpec.scala +++ b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/WorkflowEntityDescriptorFactorySpec.scala @@ -38,6 +38,12 @@ import scala.jdk.CollectionConverters.CollectionHasAsScala class WorkflowEntityDescriptorFactorySpec extends AnyWordSpec with ComponentDescriptorSuite { "Workflow descriptor factory" should { + "validate a Workflow must be declared as public" in { + intercept[InvalidComponentException] { + Validations.validate(classOf[NotPublicComponents.NotPublicWorkflow]).failIfInvalid + }.getMessage should include("NotPublicWorkflow is not marked with `public` modifier. Components must be public.") + } + "generate mappings for a Workflow with entity ids in path" in { assertDescriptor[WorkflowWithTypeLevelKey] { desc => val method = desc.commandHandlers("StartTransfer")