spring-projects / spring-integration

Spring Integration provides an extension of the Spring programming model to support the well-known Enterprise Integration Patterns (EIP)
http://projects.spring.io/spring-integration/
Apache License 2.0
1.54k stars 1.11k forks source link

Poller fixed-delay and fixed-rate support for Duration syntax #8625

Closed mauromol closed 1 year ago

mauromol commented 1 year ago

Expected Behavior

It would be nice and useful (from a configuration point of view) if <int:poller> attributes fixed-delay and fixed-rate supported the java.time.Duration syntax, with support for resolvable configuration values (via a StringValueResolver) just like @Scheduled/ScheduledAnnotationBeanPostProcessor do.

Current Behavior

fixed-delay and fixed-rate attributes in <int:poller> must be integer values, interpreted as milliseconds or amount of time-unit units. Resolvable configuration values are supported, but configuration must then specify these values as milliseconds, or provide two distinct configuration values for delay/rate and time unit.

Context

Using Spring Integration with Spring Boot 2.7.10. Duration syntax is nicely supported in a lot of places, but not in <int:poller> tag. The alternative to have maximum flexibility is to leave fixed-delay/fixed-rate in milliseconds and externalize them in configuration. But milliseconds are not so readable when resolutions of minutes or hours is needed.

artembilan commented 1 year ago

The XML configuration is not in priority these days: it is recommended to move Spring Integration configuration to Java DSL, especially with Spring Boot.

We have there a Pollers factory with a Duration variants. Feel free to use as a reference in XML. Or that <int:poller> has a ref attribute to point to the PeriodicTrigger bean which you can configure with the mentioned Duration.

However I think we indeed need to do anything to fix the PeriodicTrigger deprecated ctors, which we still use from the PollerParser:

        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PeriodicTrigger.class);
        builder.addConstructorArgValue(fixedDelayAttribute);
        if (StringUtils.hasText(timeUnit)) {
            builder.addConstructorArgValue(timeUnit);
        }

I guess one day they are going to be removed from there either way.

So, let's see if we can come up with a PeriodicTriggerFactoryBean with all the hard logic to parse a period value into a Duration! Contribution is welcome!

artembilan commented 1 year ago

I addition, I think our @Poller parser in the MessagingAnnotationPostProcessor logic does not support Duration, too.

aljopainter commented 1 year ago

I do wish that XML configuration were not de-prioritized as it has a lot of advantages over DSL and Annotation-based.

I realize that this is not the place to debate it, but I do not want to miss the opportunity to let you know that there are still some in the Spring community who prefer XML configuration.

On Wed, May 17, 2023 at 3:23 PM Artem Bilan @.***> wrote:

I addition, I think our @Poller parser in the MessagingAnnotationPostProcessor logic does not support Duration, too.

— Reply to this email directly, view it on GitHub https://github.com/spring-projects/spring-integration/issues/8625#issuecomment-1551389339, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABF7U5MYE3NKNC3EESWEGV3XGTGLPANCNFSM6AAAAAAYEYK7SM . You are receiving this because you are subscribed to this thread.Message ID: @.***>

artembilan commented 1 year ago

No, that is the right place to debate.

Give us, please, some hint what advantages you find over Java DSL?

aljopainter commented 1 year ago

A number of things:

-- Names of beans in MessageHistory and in logs are much clearer from the XML configuration -- can reference beans by name whereas with DSL you'll need to inject the bean in either the Class constructor or the Bean method -- much easier to navigate in IntelliJ from a bean reference to the bean implementation with XML configuration -- easier to compartmentalize aspects within a given .xml file .. this makes for easier testing and reuse, whereas more difficult to compartmentalize Java classes

I've pushed myself into using DSL configuration to try to better use it, and I'm still learning how best to do this, but I have found it that it nowhere as convenient as XML

On Wed, May 17, 2023 at 3:34 PM Artem Bilan @.***> wrote:

No, that is the right place to debate.

Give us, please, some hint what advantages you find over Java DSL?

— Reply to this email directly, view it on GitHub https://github.com/spring-projects/spring-integration/issues/8625#issuecomment-1551410761, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABF7U5IN2PPBT7RWGRIUJADXGTHXVANCNFSM6AAAAAAYEYK7SM . You are receiving this because you commented.Message ID: @.***>

mauromol commented 1 year ago

I also think that Spring Integration is probably one of the Spring projects where XML configuration (using namespaces) is much better than the Java counterpart (another example is probably Spring Security). The main selling point, for me, is readability: I tried to read again the chapter in Spring Integration manual regarding the Java DSL, but when the flow becomes a little more complicated it's really really hard to read its definition, IMHO. Partly because the builder pattern is not as much "natural" as an XML tag with all of its attributes set, but also because Java code formatting may not match the requirements to properly "indent" code so that the integration flow declaration is "visibly clear" (I would probably need a set of different formatting rules for the classes where I define my integration flows...). Also, lambda expressions allow for a more compact syntax, but may distract you by mixing runtime logic with actual flow definition.

Another difficulty I find in these Java DSLs (I have the same difficulty with Spring Security) is to understand what a method call is supposed to return, in order to understand which calls I should chain at which point to achieve what I want. On the contrary, the XML namespace is really clear: elements with attributes, possibly with subelements when something relates to the parent element; then, other elements, bound to the previous ones through channels or in a chain: very simple.

I know XML config is no more in fashion these days, but I think that if something works well for a given task, it shouldn't be replaced just because the trend goes somewhere else.

If I had to think of another example where XML config has been replaced, I can think of Gradle vs Maven. There, however, they have built a Groovy DSL which is really effective and can really make a difference. Gradle build scripts are for the most part really easy to read: however, I just had a quick look at Spring Integration Groovy DSL, but it's nothing near to the clearness of Gradle one, it seems like it's just an extension of the Java DSL to use Groovy language constructs. And plain Java, to write a DSL, is not quite adequate IMHO...

Just my 2 cents.

Regarding this issue: I didn't know about the ref attribute of <int:poller>, it's probably not even mentioned in the reference documentation. It's an interesting workaround, although I still feel it would be sooo natural to be able to specify Duration strings directly in fixed-rate and fixed-delay attributes :-)

artembilan commented 1 year ago

Good! Thank you for feedback.

Let me come up with some answers for you!

Names of beans in MessageHistory and in logs are much clearer from the XML configuration

Java DSL endpoint definitions also come with an id() option: https://docs.spring.io/spring-integration/docs/current/reference/html/dsl.html#java-dsl-endpoints You probably will end up with the same result in a history if you don't specify an id on XML components.

can reference beans by name whereas with DSL you'll need to inject the bean in either the Class constructor or the Bean method

There are overloaded DSL operators which accepts bean names:

    /**
     * Populate a {@link ServiceActivatingHandler} for the
     * {@link org.springframework.integration.handler.MethodInvokingMessageProcessor}
     * to invoke the {@code method} for provided {@code bean} at runtime.
     * @param beanName the bean name to use.
     * @param methodName the method to invoke.
     * @return the current {@link BaseIntegrationFlowDefinition}.
     */
    public B handle(String beanName, @Nullable String methodName) {

much easier to navigate in IntelliJ from a bean reference to the bean implementation with XML configuration

This is out of this project scope. You need to thank to your IDE to have that navigation support for an XML config. It just doesn't support such a feature for Java "config by names" 😄 . It also annoys when I try to auto-wire JdbcTemplate from auto-configuration: the IDE just doesn't see those beans coming from Spring Boot.

easier to compartmentalize aspects within a given .xml file

No one said you that you have to compose all your logic in a single IntegrationFlow. You always can come up with independent components which you can reuse in other places. See some samples of this decomposition in my Microservices Patterns project: https://github.com/artembilan/microservices-patterns-spring-integration/blob/main/outbox/src/main/java/org/springframework/integration/microservices/outbox/OutboxApplication.java

becomes a little more complicated it's really really hard to read its definition

Fully agreed. But this doesn't mean that we don't have similar problem with any design. See my previous comment: no one makes you to put everything into a single flow definition. You simply can have all the channel adapters declared in a separate methods and just references to them from the flow. The Circuit Breaker sample should give some clue how that could be configured: https://github.com/artembilan/microservices-patterns-spring-integration/blob/main/circuit-breaker/src/main/java/org/springframework/integration/microservices/circuitbreaker/CircuitBreakerApplication.java. I doubt that it is going to be much easier with an XML.

Java code formatting may not match the requirements to properly "indent"

Not sure how this could be treated as a DSL problem. You get same outcome with plain Java Stream API or Reactor Flux.

lambda expressions allow for a more compact syntax, but may distract you by mixing runtime logic with actual flow definition.

Sure! That's why we always have freedom to extract that logic into methods and use them as reference: handle(this::myBusinessLogic). You probably still use SpEL with an XML configuration though, so, I don't see technical difference with those lambdas in Java DSL...

elements with attributes, possibly with subelements

That's why I said before that you simply can declare something like Http.inboundChannelAdapter() as a top-level bean and just reference to it from flow definition. The IntegrationFlow is essentially a mimic of a <chain> in XML where we don't care what channels are between those endpoints.

The most closer variant for what you talk about wiring with channels are messaging annotations where you configure a @ServiceActivator on a business method with channel attributes and so on in other method with other messaging annotations to connect them: https://docs.spring.io/spring-integration/docs/current/reference/html/configuration.html#annotations Sometime I find it really difficult to navigate an XML from endpoint to endpoint just because they are connected through those channels. Same for these messaging annotations. Where with an IntegationFlow we have everything wired directly by those EIP-methods. We also have from(IntegrationFlow) and to(IntegrationFlow) to be able to divide logic between different (or even reusable) flows which simply can be navigated from IDE: https://docs.spring.io/spring-integration/docs/current/reference/html/dsl.html#integration-flows-composition

I just had a quick look at Spring Integration Groovy DSL, but it's nothing near to the clearness of Gradle one

I cannot agree with this since (even if I like Gradle and Groovy by itself) it is hard to determine what and how to write in that Gradle config, especially for plugin configurations. We really designed Groovy DSL similar way to Gradle style, despite it is just wrapper around Java DSL:

        @Bean
        someFlow() {
            integrationFlow { 'test' }
                    {
                        log LoggingHandler.Level.WARN, 'test.category'
                        channel { queue 'pollerResultChannel' }
                    }
        }

I'm not sure what you see here as a difference with Gradle style... And thanks to @CompileStatic and @DelegatesTo we have a good IDE support for suggestions, unlike with Gradle 😄

Sorry for a lengthy , but I tried to cover all your questions.

Of course, we are opened for suggestions to improve an API to make your developer life easier.

The ref attribute is definitely documented: https://docs.spring.io/spring-integration/docs/current/reference/html/endpoint.html#endpoint-namespace.

As we agreed here, the Duration support will be added to <poller> configuration as a task for this issue.

Thank you for your time again!

aljopainter commented 1 year ago

I'll give the id() option a shot for bean names.

I believe that there is no bean name overload for "transform()" hence I end up with a SpEL expression like @.***(#root)" which works reasonably well.

thanks

On Wed, May 17, 2023 at 5:35 PM Artem Bilan @.***> wrote:

Good! Thank you for feedback.

Let me come up with some answers for you!

Names of beans in MessageHistory and in logs are much clearer from the XML configuration

Java DSL endpoint definitions also come with an id() option: https://docs.spring.io/spring-integration/docs/current/reference/html/dsl.html#java-dsl-endpoints You probably will end up with the same result in a history if you don't specify an id on XML components.

can reference beans by name whereas with DSL you'll need to inject the bean in either the Class constructor or the Bean method

There are overloaded DSL operators which accepts bean names:

/**

  • Populate a @.*** ServiceActivatingHandler} for the
  • @.*** org.springframework.integration.handler.MethodInvokingMessageProcessor}
  • to invoke the @. method} for provided @. bean} at runtime.
  • @param beanName the bean name to use.
  • @param methodName the method to invoke.
  • @return the current @.** BaseIntegrationFlowDefinition}. / public B handle(String beanName, @Nullable String methodName) {

much easier to navigate in IntelliJ from a bean reference to the bean implementation with XML configuration

This is out of this project scope. You need to thank to your IDE to have that navigation support for an XML config. It just doesn't support such a feature for Java "config by names" 😄 . It also annoys when I try to auto-wire JdbcTemplate from auto-configuration: the IDE just doesn't see those beans coming from Spring Boot.

easier to compartmentalize aspects within a given .xml file

No one said you that you have to compose all your logic in a single IntegrationFlow. You always can come up with independent components which you can reuse in other places. See some samples of this decomposition in my Microservices Patterns project: https://github.com/artembilan/microservices-patterns-spring-integration/blob/main/outbox/src/main/java/org/springframework/integration/microservices/outbox/OutboxApplication.java

becomes a little more complicated it's really really hard to read its definition

Fully agreed. But this doesn't mean that we don't have similar problem with any design. See my previous comment: no one makes you to put everything into a single flow definition. You simply can have all the channel adapters declared in a separate methods and just references to them from the flow. The Circuit Breaker sample should give some clue how that could be configured: https://github.com/artembilan/microservices-patterns-spring-integration/blob/main/circuit-breaker/src/main/java/org/springframework/integration/microservices/circuitbreaker/CircuitBreakerApplication.java . I doubt that it is going to be much easier with an XML.

Java code formatting may not match the requirements to properly "indent"

Not sure how this could be treated as a DSL problem. You get same outcome with plain Java Stream API or Reactor Flux.

lambda expressions allow for a more compact syntax, but may distract you by mixing runtime logic with actual flow definition.

Sure! That's why we always have freedom to extract that logic into methods and use them as reference: handle(this::myBusinessLogic). You probably still use SpEL with an XML configuration though, so, I don't see technical difference with those lambdas in Java DSL...

elements with attributes, possibly with subelements

That's why I said before that you simply can declare something like Http.inboundChannelAdapter() as a top-level bean and just reference to it from flow definition. The IntegrationFlow is essentially a mimic of a in XML where we don't care what channels are between those endpoints.

The most closer variant for what you talk about wiring with channels are messaging annotations where you configure a @ServiceActivator on a business method with channel attributes and so on in other method with other messaging annotations to connect them: https://docs.spring.io/spring-integration/docs/current/reference/html/configuration.html#annotations Sometime I find it really difficult to navigate an XML from endpoint to endpoint just because they are connected through those channels. Same for these messaging annotations. Where with an IntegationFlow we have everything wired directly by those EIP-methods. We also have from(IntegrationFlow) and to(IntegrationFlow) to be able to divide logic between different (or even reusable) flows which simply can be navigated from IDE: https://docs.spring.io/spring-integration/docs/current/reference/html/dsl.html#integration-flows-composition

I just had a quick look at Spring Integration Groovy DSL, but it's nothing near to the clearness of Gradle one

I cannot agree with this since (even if I like Gradle and Groovy by itself) it is hard to determine what and how to write in that Gradle config, especially for plugin configurations. We really designed Groovy DSL similar way to Gradle style, despite it is just wrapper around Java DSL:

  @Bean
  someFlow() {
      integrationFlow { 'test' }
              {
                  log LoggingHandler.Level.WARN, 'test.category'
                  channel { queue 'pollerResultChannel' }
              }
  }

I'm not sure what you see here as a difference with Gradle style... And thanks to @CompileStatic and @DelegatesTo we have a good IDE support for suggestions, unlike with Gradle 😄

Sorry for a lengthy , but I tried to cover all your questions.

Of course, we are opened for suggestions to improve an API to make your developer life easier.

The ref attribute is definitely documented: https://docs.spring.io/spring-integration/docs/current/reference/html/endpoint.html#endpoint-namespace .

As we agreed here, the Duration support will be added to configuration as a task for this issue.

Thank you for your time again!

— Reply to this email directly, view it on GitHub https://github.com/spring-projects/spring-integration/issues/8625#issuecomment-1551622789, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABF7U5KXXNG3UIZ767RHJQLXGTV4DANCNFSM6AAAAAAYEYK7SM . You are receiving this because you commented.Message ID: @.***>

artembilan commented 1 year ago

I believe that there is no bean name overload for "transform()"

Yeah... I see. Right, we have something like this for splitter:

public B split(String expression) {

split(String beanName, @Nullable String methodName) {

But only the first variant for transform(). I think I don't see a problem adding transform(String beanName, @Nullable String methodName) variant.

Please, raise a new GH issue.

Thank you for the pointer!

aljopainter commented 1 year ago

Added issue: https://github.com/spring-projects/spring-integration/issues/8626

On Wed, May 17, 2023 at 6:16 PM Artem Bilan @.***> wrote:

I believe that there is no bean name overload for "transform()"

Yeah... I see. Right, we have something like this for splitter:

public B split(String expression) {

split(String beanName, @Nullable String methodName) {

But only the first variant for transform(). I think I don't see a problem adding transform(String beanName, @Nullable String methodName) variant.

Please, raise a new GH issue.

Thank you for the pointer!

— Reply to this email directly, view it on GitHub https://github.com/spring-projects/spring-integration/issues/8625#issuecomment-1551698643, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABF7U5PGHWXK24AOKPYVGK3XGT2UBANCNFSM6AAAAAAYEYK7SM . You are receiving this because you commented.Message ID: @.***>

mauromol commented 1 year ago

Java code formatting may not match the requirements to properly "indent"

Not sure how this could be treated as a DSL problem. You get same outcome with plain Java Stream API or Reactor Flux.

Hi Artem, first of all I would like to say that the problems I see with Java DSL are not about features, but rather about readability and ease of writing. Ok, perhaps if I were comfortable with Java DSL it would be easier, or perhaps it's my limit, but I find really hard to read a complex flow written with Java DSL, while I can follow it quite easily in XML. So, the "indentation" problem I described is not a DSL problem from a feature point of view, but simply it's due to the fact that (in my opinion) the Java DSL is not the best language/technology to use to describe a flow composition.

Sure! That's why we always have freedom to extract that logic into methods and use them as reference: handle(this::myBusinessLogic). You probably still use SpEL with an XML configuration though, so, I don't see technical difference with those lambdas in Java DSL...

You're right. But SpEL expressions should be short and they are put into attributes, so they are in some way confined. You have to use them sparingly. In Java code you're free to do anything. Yes, you can decompose things to improve readability, but still you end up with code describing something, rather than with an actual description of that thing. It's hard for me to explain, I hope you at least get the concept...

The most closer variant for what you talk about wiring with channels are messaging annotations where you configure a @ServiceActivator on a business method with channel attributes and so on in other method with other messaging annotations to connect them: https://docs.spring.io/spring-integration/docs/current/reference/html/configuration.html#annotations Sometime I find it really difficult to navigate an XML from endpoint to endpoint just because they are connected through those channels. Same for these messaging annotations. Where with an IntegationFlow we have everything wired directly by those EIP-methods. We also have from(IntegrationFlow) and to(IntegrationFlow) to be able to divide logic between different (or even reusable) flows which simply can be navigated from IDE: https://docs.spring.io/spring-integration/docs/current/reference/html/dsl.html#integration-flows-composition

I'm not sure I can fully follow you. I use annotations sparingly and only to avoid the use of interfaces or to describe "singleton" components in my integration flows. The main flow description is written in XML and channels are declared in XML as well. I agree with you that when you start to mix XML and annotations it can become a mess.

I cannot agree with this since (even if I like Gradle and Groovy by itself) it is hard to determine what and how to write in that Gradle config, especially for plugin configurations. We really designed Groovy DSL similar way to Gradle style, despite it is just wrapper around Java DSL:

Documentation is of course essential. XML has the benefit to guide you with a schema, a Groovy DSL does not have a schema and often the IDE is not really helpful (that's the case for Gradle Groovy DSL too, at least in Eclipse), however that is not the point.

      @Bean
      someFlow() {
          integrationFlow { 'test' }
                  {
                      log LoggingHandler.Level.WARN, 'test.category'
                      channel { queue 'pollerResultChannel' }
                  }
      }

What disturbs me are all those methods with multiple parameters. Why a "{" block after integrationFlow { 'test' }? What does it mean? What are LoggingHandler.Level.WARN and 'test.category'? Indeed, these are method calls, they are not pure description.

The following is pure description instead, although it's actually mapped to method calls under the hood:

publishing {
    publications {
        mavenJava(MavenPublication) {
            from components.java
            artifactId 'myartifact'
        }
    }

    repositories {
        maven {
            url 'myRepoUrl'
            credentials {
                username = 'myUserName'
                password = 'myPassword'
            }
            allowInsecureProtocol = true
        }
    }
}

So you have just blocks describing components (just like XML elements), properties (just like XML attributes) and nesting of blocks to describe nested components. Of course I'm simplifying. What I'm trying to say is that I like my flow descriptions to be just descriptions, not imperative code, even if I try to disguise those methods calls with curated methods names using the chain pattern.

The ref attribute is definitely documented: https://docs.spring.io/spring-integration/docs/current/reference/html/endpoint.html#endpoint-namespace.

You're right, sorry, I was looking at the wrong place: https://docs.spring.io/spring-integration/docs/5.4.11/reference/html/core.html#polling-consumer On the above link I can't find mentions of ref. Still, looking at the right page, it's not that easy to grasp that ref can point to a PeriodicTrigger bean, it just says it may point to a top-level <int:poller>.

artembilan commented 1 year ago

it's not that easy to grasp that ref can point to a PeriodicTrigger

Oh! My fault. The attribute we are looking for is a trigger:

Reference to any Spring-configured bean that implements the org.springframework.scheduling.Trigger interface. However, if this attribute is set, none of the following attributes must be specified: fixed-delay, fixed-rate, cron, and ref. Optional.

Re. Groovy DSL.

I don't see difference between integrationFlow { 'test' } { definition and your mavenJava(MavenPublication) {. That log LoggingHandler.Level.WARN, 'test.category' is exactly what you show with an `url 'myRepoUrl'. It is not fully clear why would one need that:

credentials {
                username = 'myUserName'
                password = 'myPassword'
            }

when it could be as simple as credentials 'myUserName', 'myPassword'. Why allowInsecureProtocol = true, but not just allowInsecureProtocol true. Too much inconsistency in that Gradle DSL.

However I think you are right and we are not fully following Gradle style since don't have those intermediate containers like the mentioned credentials. Either way we have to get used to that Gradle DSL and it is not the same for all the plugins.

And here is a screenshot for Groovy DSL in my IDE: image

As you see it does give us those parameter descriptions.

However I got you point about description. I'm not sure what could be better than setters and builder pattern in Java do describe something. Here is a sample of JPA channel adapter:

.handle(Jpa.retrievingGateway(entityManagerFactory)
                            .jpaQuery("from Student s where s.id = :id")
                            .expectSingleResult(true)
                            .parameterExpression("id", "headers[payloadId]"))

Why do you find it so bad than similar XML variant:

    <int-jpa:retrieving-outbound-gateway id="retrievingJpaOutboundGateway"
        entity-manager-factory="entityManagerFactory"
        auto-startup="true"
        entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
        order="1"
        max-results="55"
        delete-after-poll="true"
        flush-after-delete="true"
        request-channel="in"
        reply-channel="out"
        reply-timeout="100"
        expect-single-result="true"
        requires-reply="false"/>

?

With a handle() we say that it is a service activator or an outbound gateway. With a Jpa.retrievingGateway() factory we say that it is going to be a gateway for SELECT via JPA. The rest is just a result of builder pattern method chaining which shows us exactly options and their value. How that is different from an equivalent XML?

If you are not comfortable to put them together into an IntegrationFlow, feel free to use @ServiceActivator which would give you those input and output channel options. However you mentioned a <chain> where you "mess" several nested components. How is that different then to an IntegationFlow?

mauromol commented 1 year ago

it's not that easy to grasp that ref can point to a PeriodicTrigger

Oh! My fault. The attribute we are looking for is a trigger:

Ok, this is clear now, thanks a lot for pointing that out!

Re. Groovy DSL.

I don't see difference between integrationFlow { 'test' } { definition and your mavenJava(MavenPublication) {. That log LoggingHandler.Level.WARN, 'test.category' is exactly what you show with an `url 'myRepoUrl'. It is not fully clear why would one need that:

credentials {
              username = 'myUserName'
              password = 'myPassword'
          }

when it could be as simple as credentials 'myUserName', 'myPassword'.

Because here you loose parameter names, which describe what are you doing. In this example it's quite clear what myUserName and myPassword are, but in other context that may not be the case. Regarding integrationFlow { 'test' } {, there are two blocks one after the other and it's not explicit what they should do and what is their mutual relationship. Unless you search for documentation, of course.

Why allowInsecureProtocol = true, but not just allowInsecureProtocol true. Too much inconsistency in that Gradle DSL.

I believe that allowInsecureProtocol true works as well, something comes into my mind, but I'm not sure now. I agree there is inconsistency here and there. I just wanted to point out a good example of Groovy DSL, not a perfect one :-)

However I got you point about description. I'm not sure what could be better than setters and builder pattern in Java do describe something. Here is a sample of JPA channel adapter:

As I said, I think the problem is just Java. Which I love and I think it's great, but it's not the best solution for this problem. As always, IMHO.

With a handle() we say that it is a service activator or an outbound gateway. With a Jpa.retrievingGateway() factory we say that it is going to be a gateway for SELECT via JPA. The rest is just a result of builder pattern method chaining which shows us exactly options and their value. How that is different from an equivalent XML?

Given that XML works and its support is very good in Spring Integration, I'll try to reverse the question: why is XML so bad that is somewhat being deprecated? :-) I guess it's about maintenance, but also about AOT compiling it (i.e.: GraalVM), because I guess XML processing would need to be refactored to try to remove reflection, am I right? Type safety is less important IMHO because Spring Tooling is quite good on XML editing, although less effort has gone there since STS 4.

artembilan commented 1 year ago

Yeah... So, I think something like this we have so far:

aggregate {
    id 'aggregator'
    outputProcessor { it.one }
    expireGroupsUponCompletion false
}

Is what you are talking about descriptive style.

But others are really different and not so readable. Like this sample for the splitter:

split(Object, { it }) {
    id 'splitterEndpoint'
}

where it is not clear what are those Object and closure with it.

This one does look well, too:

poller {
    it.fixedDelay(10)
        .maxMessagesPerPoll(1)
}

Although it has some visibility level. for the poller property there is just no Groovy @DelegatesTo like we do with that aggregate before. Just because we use here directly Java EndpointSpec class, no groovy wrapper.

Well, that something to think and play with.

Feel free to raise an new GH issue about this Groovy DSL concern.

Thank you for feedback and contribution is welcome!

artembilan commented 1 year ago

Hi @mauromol !

If you don't mind, please, take a look into this PR: https://github.com/spring-projects/spring-integration/pull/8636.

Essentially what I did is something like this in Groovy DSL:

headerFilter {
    patternMatch false
    headersToRemove "notAHeader", "headerToRemove"
}

Kinda exactly what we discussed with you before about an aggregate.

I understand that you might be interested in something more in Groovy style which would mimic an XML configuration, probably fully without that integationFlow { } wrapper, but that would be a bit different story and let's move to there in a baby steps for now.