1

I have a class which acts as a Adaptor between an HTTP request and our Application's custom domain request. So every Http request element: URI, headers, content are mapped to our customized domain object elements.

Another class DataMapper which performs serialization/deserilaiztion of content. This class is used by the adaptor to encode/decode content of HttpRequest.

DataMapper

public abstract class DataMapper {

    /**
     * Factory method to create Data mapper types
     * @param mediaType: Type for which Datamapper is to be created
     * @return
     */
    public static DataMapper getMapper(String mediaType) {
        MediaType type = MediaType.findType(mediaType); 

        switch(type) {

        case JSON:
            return new JSONDataMapper();

        case XML:
            return new XMLDataMapper();

        }
        throw new IllegalArgumentException("Invalid media Type: " + mediaType );

    }

    /**
     * Serialize general obj to XML
     * 
     */
    public abstract String serialize(Object ob);

    /**
     * Deserialize general obj to XML
     * 
     */
    public abstract Object deserialize(String obj);

}

Adaptor

public class HttpToCustomDomainConverter {

    private DataMapper dataMapper;     

    /**
     * @param httpRequest: HTTP request
     * @param domainReq: Domain request 
     * @return nothing
     * @return Converts HTTP request to Domain Request
     */
    public void httpToCustomDomainRequest(HttpServletRequest httpRequest, CustomDomainRequest domainReq) {

        domainReq.setRequestIdentifier(httpRequest.getHeader("X-Domain-RI"));

        String acceptType = httpRequest.getHeader("Accept");
        String contentTypeHeader = httpRequest.getContentType();

        String serializedPayload = getPayload(httpRequest, contentType);

        dataMapper = DataMapper.getMapper(contentType);

        switch(httpMethod){

        case POST:
        case PUT:

            Object content = dataMapper.deserialize(serializedPayload));
            domainReq.setContent(content);

            break;

        case GET:
        case DELETE:
            break;
        }

        // ........
   }   
}

Question:

I want my code to follow SOLID principles, the one I am worried about in this is Dependency Injection.

dataMapper = DataMapper.getMapper(contentType);
dataMapper.deserialize(serializedPayload));

Here I take out http requestContentType header and then find it's corresponding DataMapper (XML or JSON) and then serialize/deserialize content.

So shall I pass the specific implementation of DataMapper (XmlDataMapper or JsonDataMapper) in the constructor of this class to follow DI.

Or my code is correct in locating the DataMapper at run time based on contentType in request.

Any advice is appreciated.

  • Is dataMapper used somewhere else within the converter? Any other public method that may cause a NullPointerException? Do you need to keep the reference to the dataMapper? Is the Http converter "singleton" or there's an instance for each http request? – Laiv Aug 4 '17 at 11:34
  • @Laiv: Yes, there are other methods related to response which also assign DataMapper for ex: for response dataMapper is intialized based on AcceptType header of HTTP. No it's not singleton – Siddharth Trikha Aug 4 '17 at 11:48
  • 2
    FYI, locating the right data mapper according to the Content-Type at runtime is what Spring, CXF and others tools like that do.Bascally you would insject a factory that return the right data mapper (either a new instance of a singleton thread safe one). – Walfrat Aug 4 '17 at 11:56
4

Your line,

I want my code to follow SOLID principles, the one I am worried about in this is Dependency Injection.

is confusing. Are you worried that it's not using dependency injection (DI)? If so, I'd say you are right to consider it, but you may not be right to be worried.

By using this service locator, rather than using DI, then you are potentially making your code harder to test as you cannot mock that data mapper during the tests. However, if these mappers are side-effect free, then you may have no need to mock them. DI purists, such as myself, might cringe at this locator, but pragmatically, it might be your best choice here.

  • So you suggest using a service locator might be fine in the above case ? These datamappers might throw exception s related to data parsing. But for purely usibg DI in my case I will need to process request before to find datamapper and then pass it. So what should be the correct approach? – Siddharth Trikha Aug 4 '17 at 15:38
  • We can not say what should you do. However, David pointed to a key factor here. Testing. If you are concerned about testing, do DI. If you don't, keep the service locator. Be pragmatic and keep it as simple as possible. – Laiv Aug 4 '17 at 20:50
  • "These datamappers might throw exception s related to data parsing". Then make sure you write tests to ensure those exceptions are properly handled (and "properly handled" might mean "let the exception bubble up"). – David Arno Aug 4 '17 at 20:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.