0

I have a SpringBoot 2.2.6 webapp and the customer ask me to use spring-integration-http for the endpoint.

Now, my goal is to be able to profiling @Transformers.

For example if I design an interface like follow:

public interface CommonTransformer {
   public Integer transform(AObject t, @Header String some);

   public Integer transform(BObject t, @Header String some);
}

And a class like follow:

@Component
@Profile("unicredit")
public class TestTransformer implements CommonTransformer {
    
  @Override
  @Transformer
  public Integer transform(AObject t, @Header("case") String caso) {
    return t.getId();
  }

  @Override
  @Transformer
  public Integer transform(BObject t, @Header("case") String caso) {
    return t.getId();
  }
}

And the following endpoint:

@Bean
public IntegrationFlow test(Jackson2JsonObjectMapper obj, CommonTransformer transformer) {
    return IntegrationFlows.from(Http.inboundGateway("/api/test/{id_a}/{id_b}")
            .requestMapping(m -> m.methods(HttpMethod.GET))
                .replyChannel("reply")
                .payloadExpression("new it.integration.http.bean.AObject(#pathVariables.id_a, #pathVariables.id_b)")
                .requestPayloadType(AObject.class))
            .enrichHeaders(h -> h.header("case", "test1"))
            .transform(transformer)
            .transform(new ObjectToJsonTransformer(obj))
            .channel("httpRequest")
            .get();
    
}

@Bean
public IntegrationFlow test2(Jackson2JsonObjectMapper obj, CommonTransformer transformer) {
    return IntegrationFlows.from(Http.inboundGateway("/api/test2/{id_b}")
            .requestMapping(m -> m.methods(HttpMethod.GET))
                .replyChannel("reply")
                .payloadExpression("new it.integration.http.bean.BObject(#pathVariables.id_b)")
                .requestPayloadType(BObject.class))
            .enrichHeaders(h -> h.header("case", "test2"))
            .transform(transformer)
            .transform(new ObjectToJsonTransformer(obj))
            .channel("httpRequest")
            .get();
    
}

This way, if I call the first or the second endpoint the correct @Transformer will be called just specifying the interface as endpoint parameter.

This allow me to create for example another implementation like:

@Component
@Profile("ubs")
public class TestTransformer implements CommonTransformer {

  UBSSOAPClient client;

  @Override
  @Transformer
  public Integer transform(AObject t, @Header("case") String caso) {
    Object obj = client.getSome();
    return someMapper.mapToAObject(obj);
  }

  @Override
  @Transformer
  public Integer transform(BObject t, @Header("case") String caso) {
    Object obj = client.getSome();
    return someMapper.mapToBObject(obj);
  }
}

This kind of profiling is vital for the project I'm developing, but if I have two endpoint like this:

@Bean
public IntegrationFlow test(Jackson2JsonObjectMapper obj, CommonTransformer transformer) {
    return IntegrationFlows.from(Http.inboundGateway("/api/test/{id}")
            .requestMapping(m -> m.methods(HttpMethod.GET))
                .replyChannel("reply")
                .payloadExpression("#pathVariables.id)
                .requestPayloadType(Integer.class))
            .transform(transformer)
            .transform(new ObjectToJsonTransformer(obj))
            .channel("httpRequest")
            .get();
}

@Bean
public IntegrationFlow test(Jackson2JsonObjectMapper obj, CommonTransformer transformer) {
    return IntegrationFlows.from(Http.inboundGateway("/api/test2/{id}")
            .requestMapping(m -> m.methods(HttpMethod.GET))
                .replyChannel("reply")
                .payloadExpression("#pathVariables.id)
                .requestPayloadType(Integer.class))
            .transform(transformer)
            .transform(new ObjectToJsonTransformer(obj))
            .channel("httpRequest")
            .get();
}

The trick doesn't work because they have the same Integer parameter within the payload. Therefore the question is can I have an interface like:

public interface CommonTransformer {
 public Integer transformA(AObject t, @Header String some, Other params);

 public Integer transformB(BObject t, @Header String some);
 .......
 other methods
}

Several profiled implementation and calling the appropriate method in some way at this point:

@Bean
public IntegrationFlow test(CommonTransformer transformer) {
     .....
     .....
     .transform(transformer::transformA) // or something like that??
}

Clearly I want to pass to the method the payload the headers I enriched (or setted with #pathVariables or #requestParams expression).

Maybe the question (and the code I have written) may seem dummy but I'm absolutely new to spring-integration and I have to do so much thing in a very short time..

Any help is appreciated.

CoderJammer
  • 599
  • 3
  • 8
  • 27

1 Answers1

0

Sorry, we don't see a relevance between your requestPayloadType(Integer.class) and some CommonTransformer method: doesn't look like you just have a method based on the Integer type. Please, elaborate what you'd like to call for /api/test and what for /api/test2.

The method is selected by the payload type from the message which has a contract like this:

public interface Message {

/**
 * Return the message payload.
 */
T getPayload();

/**
 * Return message headers for the message (never {@code null} but may be empty).
 */
MessageHeaders getHeaders();

}

So, it doesn't matter how may params you are going to have without a @Header (or with a @Payload), all of them can be populated only with the payload from that message. And yes: converted, respectively if types don't match.

You can use a method reference, but it has to match to the GenericTransformer contract. And get access to headers you'd need to have an input as a whole Message and use this variant:

.transform(Message.class, transformer::transformA)

Where it has to look like this:

Integer transformA(Message<AObject> message);
Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Thanks a lot, I will try the method reference as soon as I can. What I would realize is to have x endpoint and x transformers, and I would like to call them by a various implementation of a single Interface wich is profiled and than loaded if the spring profile is specified when we build project. – CoderJammer Jul 05 '22 at 10:47
  • Well, if you are profiling you could just have a `GenericTransformer` impls per type and per profile and use it as simple as `.transform(myTransformer)` injection. – Artem Bilan Jul 05 '22 at 13:35