mardi 20 octobre 2020

Making Spring's @Service and @Configuration class more generic using patterns?

The idea is to use some kind of (custom) design pattern (or any other Java constructs such as parametrized types etc) to make @Configuration and @Service classes more generic and general.

The problem:

Part of my Spring Boot application acts like a client, i.e. it uses some SOAP Web services. I'm using exactly seven (in future possibly more) services. Classes which I'm using to send request and receive response are generated by the Maven JAXB2 plugin based on WSDL. In this post, I'm gonna outline the simplest services:

HelloWorld

Controller layer:

@Autowired
private HelloWorldClient helloWorldClient;

@RequestMapping(value = "/helloWorld", method = RequestMethod.POST)
@ResponseBody
public HelloWorldResponse helloWorldRequest(@RequestParam(value = "myValue") String myValue) {

    HelloWorldResponse response = helloWorldClient.getValue(myValue);

    return response;
}

Configuration for service class

@Configuration
public class HelloWorldConfiguration {

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath("com.zesium.arvato.model"); //this is package where I placed generated classes from wsdl scheme
        return marshaller;
    }

    @Bean
    public HelloWorldClient helloWorldClient(Jaxb2Marshaller marshaller) {
        HelloWorldClient client = new HelloWorldClient();
        client.setDefaultUri(""); 
        client.setMarshaller(marshaller);
        client.setUnmarshaller(marshaller);
        return client;
    }

}

Service class

@Service
public class HelloWorldClient extends WebServiceGatewaySupport {
    
    @Autowired
    private ObjectFactory objectFactory;

    public HelloWorldResponse getValue(String myValue) {

        HelloWorld request = objectFactory.createHelloWorld();
        JAXBElement<String> value = objectFactory.createHelloWorldMyValue(myValue);
        request.setMyValue(value);

        HelloWorldResponse response = (HelloWorldResponse) getWebServiceTemplate()
                .marshalSendAndReceive("https://clienttesthorizon.horizonafs.com/AFSServices/AFSService.svc/basicHttpBinding", 
                        request, new SoapActionCallback("http://tempuri.org/IAFSService/HelloWorld"));

        return response;
    }

}

Now, as I mentioned I have seven more of these "triplets" for each service one triplet. As expected, other services in the getValue() are accepting different number of parametears (String, ints and BigDecimals).

The question is, is there some kind of design pattern or Spring "way" of making this more generic? Meaning, to write some kind of "template" @Serivce class, along with @Configuration class to facilitate the idea?

Something roughly like this:

public class GenericClient<R,C> extends WebServiceGatewaySupport {

R response; //R would represent response (like HelloWorldRespons)
            //C would represent different serivce class clients

public GenericClient<R, T>(R r, C c){
    this.response = r;
}

@Autowired
private ObjectFactory objectFactory;

public R getValue(String myValue) {

    C request = objectFactory.createC(C.class);
    
    //Call to some method which will dynamically during runtime figure out which implementation to call

    R response = (R) getWebServiceTemplate()
            .marshalSendAndReceive("https://clienttesthorizon.horizonafs.com/AFSServices/AFSService.svc/basicHttpBinding", 
                    request, new SoapActionCallback("http://tempuri.org/IAFSService/ServiceName"));

    return response;
}

}

I know this is wrong, but I don't have any idea on how to approach this, and I've been doing backend for one and a half year at this point. I know this is very broad question, but if anyone could give me any pointers where to look for, maybe a specific design pattern or something similar, that would be excellent.

Aucun commentaire:

Enregistrer un commentaire