Service Locator vs Dependency Injection – Which Design Pattern to Use?

dependency-injectiondesign-patternsinversion-of-controlobject-oriented-designservice-locator

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.

Best Answer

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.