Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
Showing results for 
Search instead for 
Did you mean: 
Active Contributor

Dependency Injection

There is many a true word, Spoken Inject

One line summary:-

One way to write OO programs with many small classes with less lines of code.

Back Story

The other day there was a blog on SCN about Dependency injection.

I thought – I know what that is – if an object (say a car object) needs an engine object to work, you don’t have the car object create the engine object, you pass in the engine object through the car objects constructor.

I had thought that was solely concerned with unit testing, but if you look at the comments at the bottom, when I started talking about this on the blog comments, people soon put me right, it turns out it has a much wider scope.

As soon as I realised I was barking up the wrong tree, I read all I could on the subject, for example …

… ending with this blog by Jack Stewart

I always thought the idea was great – often you have to create a bunch of objects and then “wire them together” by passing them into each other’s constructors so they know about each other.

This gives you the flexibility to pass in subclasses to alter the behaviour of the application – as I said I had first heard about this in the context of unit testing, but when I thought about it again naturally you can pass in any sort of subclass to change the way the program runs e.g. different subclass based on whatever criteria makes sense, just like the BADI filter mechanism.

That is a wonderful thing to be able to do, and subclassing is one of the few benefits of OO programming that one of my colleagues can get his head around, but it does tend to involve a lot of “boiler plate” programming i.e. lots of CREATE OBJECT statements, passing in assorted parameters.

Many Small Classes, make Light Work

The idea is that the smaller and more focused your classes are, the easier they are to re-use and maintain. An OO principle is that a class should only have one reason to change i.e. it should do one thing only. If you follow that principle you get loads of benefits, but you have to create loads of classes in your program.

When I first started playing around with OO programming I was too lazy to keep writing CREATE OBJECT so I made everything static. That is not actually a sensible thing to do just to avoid work, as then you can’t subclass things. SAP itself found that out when they initially made ABAP proxy classes static.

The NEW Objects on the Block

In the Java programming language you create objects by saying GOAT = NEW GOAT as opposed to CREATE OBJECT GOAT.

In the “Head First Design Patterns Book” it gives a bunch of about five rules of programming which every Java programmer should aspire to but are in fact impossible to follow in real life.

One of those revolved around the rule being never to use the NEW statement because that hard coded the exact type of class you were creating, but how can you create objects if the only way to create them is to use the NEW statement?

In both Java and ABAP interfaces come into play here, you declare the ANIMAL object as an interface of type FARM ANIMAL (which GOAT implements) and say CREATE OBJECT ANIMAL TYPE GOAT. Perhaps a better example is in ABAP2XLS when you declare the object that writes out the file as an interface and then create it using the TYPE of the EXCEL version you want e.g. 2007.

Now you are always going to have to say the specific type (subclass) you want somewhere, but is it possible to decouple this from the exact instant you call the CREATE OBJECT statement?

Since you can have a dynamic CREATE OBJECT statement, you would think so, but how does this apparent diversion link back to what I was talking about earlier?

Jack Black and his blog Silver

Going back to Dependency Injection the blog by Jack Stewart contained a link to download some sample code. I downloaded it, had a look, thought it was great, and then totally re-wrote it. That is no reflection on the quality of the original; I am just physically incapable of not rewriting every single thing I come across.

I am going to include a SAPLINK file in text format at the end of this blog, but first I shall go through the code, top down. Firstly, this test program shows exactly what I am trying to achieve i.e. the same thing in less lines of code.

I have created some dummy Y classes which just have constructors to pass in a mixture of object instances and elementary data object parameters, my dear Watson. They only have one method each, just to write out if they are a base class or a subclass. The important thing is the effort involved to create them.

The Da Vinci Code Samples

First of all, a basic structure to get some elementary parameters and say if we want to use a test double or not. I am sticking with the unit test concept for now, but as I mentioned, you can pass in any old subclass you want, according to the good old, every popular, Liskov Substitution principle.

* Show two ways to create linked objects, one using dependency injection
REPORT  y_injection_test.

PARAMETERS : p_valid TYPE sy-datum,
TYPE werks_d,

= sy-datum.
= '3116'.

PERFORM do_it_the_long_way.
PERFORM do_it_the_short_way.

It’s a Long Long Way, from there to here

Firstly, the traditional way….

*&      Form  DO_IT_THE_LONG_WAY
* Normal way of doing things
FORM do_it_the_long_way .
DATA: lo_logger        TYPE REF TO ycl_test_logger.
DATA: lo_db_layer      TYPE REF TO ycl_test_db_layer.
DATA: lo_mock_db_layer TYPE REF TO ycl_test_mock_db_layer.
DATA: lo_simulator     TYPE REF TO ycl_test_simulator.

CREATE OBJECT lo_logger.

IF p_test = abap_true.

CREATE OBJECT lo_mock_db_layer
= lo_logger
= p_valid.

CREATE OBJECT lo_simulator
= p_werks
= lo_mock_db_layer
= lo_logger.


CREATE OBJECT lo_db_layer
= lo_logger
= p_valid.

CREATE OBJECT lo_simulator
= p_werks
= lo_db_layer
= lo_logger.


->say_who_you_are( ).


ENDFORM.                    " DO_IT_THE_LONG_WAY

Get Shorty

Now we do the same thing, using a Z class I created to use dependency injection.

*&      Form  DO_IT_THE_SHORT_WAY
*  Using Constructor Injection
FORM do_it_the_short_way .
* Local Variables
DATA: lo_simulator  TYPE REF TO ycl_test_simulator.

=>during_construction( :
= 'ID_PLANT_ID' use_value = p_werks ),
= 'ID_VALID_ON' use_value = p_valid ).

IF p_test = abap_true.
"We want to use a test double for the database object
=>instead_of( using_main_class = 'YCL_TEST_DB_LAYER'

=>create_via_injection( CHANGING co_object = lo_simulator ).

->say_who_you_are( ).

ENDFORM.                    " DO_IT_THE_SHORT_WAY

I think the advantage is self-evident – the second way is much shorter, and it’s got Big Feet.

If the importing parameter of the objectconstructor was an interface it would not matter at all. You just pass the interface name in to the INSTEAD_OF method as opposed to the main class name.

I have done virtually no error handling in the below code, except throwing fatal exceptions when unexpected things occur. This could be a lot more elegant, I am just demonstrating the basic principle.

Firstly the DURING CONSTRUCTION method analyses elementary parameters and then does nothing more fancy than adding entries to an internal table.

* Local Variables
DATA: lo_description       TYPE REF TO cl_abap_typedescr,
TYPE string ##needed,
TYPE string,
LIKE LINE OF mt_parameter_values.

-identifier = for_parameter.

CREATE DATA ls_parameter_values-do_value LIKE use_value.
GET REFERENCE OF use_value INTO ls_parameter_values-do_value.

CHECK sy-subrc = 0.

CALL METHOD cl_abap_structdescr=>describe_by_data_ref
= ls_parameter_values-do_value
= lo_description
= 1
OTHERS               = 2.

IF sy-subrc <> 0.

SPLIT lo_description->absolute_name AT '=' INTO ld_dummy ld_data_element_name.

-rollname = ld_data_element_name.

INSERT ls_parameter_values INTO TABLE mt_parameter_values.

It’s the same deal with the INSTEAD_OF method for saying what exact subclass you want to create, except it’s even simpler this time.

METHOD instead_of.
* Local Variables
DATA: ls_sub_classes_to_use LIKE LINE OF mt_sub_classes_to_use.

-main_class = using_main_class.
-sub_class  = use_sub_class.

"Add entry at the start, so it takes priority over previous
"similar entries
INSERT ls_sub_classes_to_use INTO mt_sub_classes_to_use INDEX 1.


Now we come to the main CREATE_BY_INJECTION method.  I like to think I have written this as close to plain English as I can, so that this is more or less elf-explanatory.

METHOD create_via_injection.
* Local Variables
DATA: lo_class_in_reference_details  TYPE REF TO cl_abap_refdescr,
TYPE REF TO cl_abap_typedescr,
TYPE REF TO cl_abap_typedescr,
TYPE seoclass-clsname,
TYPE seoclass-clsname,
LIKE LINE OF mt_created_objects,
TYPE abap_parmbind_tab.

* Determine the class type of the reference object that was passed in
  lo_class_in_reference_details ?= cl_abap_refdescr
=>describe_by_data( co_object ).
= lo_class_in_reference_details->get_referenced_type( ).
= lo_class_in_type_details->get_relative_name( ).

"See if we need to create the real class, or a subclass
= ld_class_passed_in
= lo_class_in_type_details
= ld_class_type_to_create
= lo_class_to_create_type_detail ).

READ TABLE mt_created_objects INTO ls_created_objects WITH TABLE KEY clsname = ld_class_type_to_create.

IF sy-subrc = 0.
"We already have an instance of this class we can use
    co_object ?= ls_created_objects

"See if the object we want to create has parameters, and if so, fill them up
( EXPORTING io_class_to_create_type_detail = lo_class_to_create_type_detail
IMPORTING et_signature_values            = lt_signature_values ).

( EXPORTING id_class_type_to_create = ld_class_type_to_create
= lt_signature_values       " Parameter Values
CHANGING  co_object               = co_object ).              " Created Object


There is not a lot of point in drilling into this any further – I would encourage you to download the SAPLINK file, and then run this in debug mode to see what is happening.

In summary, I am always on the lookout for ways to reduce the so called “boiler plate” code, so the remaining code can concentrate on what the application is supposed to be doing as opposed to how it is doing it. This dependency injection business seems ideally suited so this purpose.

Now, while I am here.

Did I mention I am giving a speech at the “Mastering SAP Technology 2014” conference at Melbourne on the 31/03/2014 – it’s about unit testing of ABAP programs.

What’s that? I’ve already mentioned this? Many times?

Oh dear, that must have slipped my mind. In that case I won’t go on about it, and I’ll sign off.

Cheersy Cheers


Labels in this area