Exception CX_SY_REF_IS_INITAL - abap

I'm setting up a Method call from a class
DATA: r_info TYPE REF TO zcl_sv_job_offline_ctrl.
CALL METHOD r_info->create
EXPORTING
is_data = lr_test_record.
And receiving the following errors:
CX_SY_REF_IS_INITAL
You are trying to access a component with a 'ZERO' object reference (points to nothing). Variable: "R_INFO".
Am I missing something?

You missed to create the object.
so you need to to:
create object r_info.
or
r_info = new zcl_sv_job_offline_ctrl( ).
or if there is a "factory method" ( what your 'create' method indicates )
r_info = zcl_sv_job_offline_ctrl=>create( is_data = lr_test_record ).
Your Exception tells you that the reference ( r_info ) is not connected with an object on the heap. So you need to do one of the above steps and then it should work. ( depending on your class )

Sorry, I don't have the rep to comment just yet...
I notice that your class is a Z so I'm wondering if you are trying to create a singleton class. In which case. Your 'Create' should be static. Your Constructor private and your Instance in a private attribute.
From the other comments, I agree, your question is missing some key details to provide an accurate answer.
If IO_DISPATCHER is part of the constructor and you are unable to pass a value, you need to dig a little deeper into the purpose of the class. See if you can give it what it wants. Try a 'where used' and check out the other usages of the class. You might find you are looking at the wrong class, or at least approaching from the wrong direction.
If create is some method on the class and it is not static then you will never get it to work until you create an instance of the class.
Another thought that comes to mind is that you might be in the right place and just doing the wrong thing. Check your globals to see if there is already an instance of the class and you are trying to access something via declaration as data rather than using the global instance??
All guess work without more details.

Thanks all.
The solution was simply to instantiate the parent classes (properly), enabled me to instantiate the class in question.

Related

Can define variables as references to local classes defined in another program?

I have a program ZPROG1_TEST where I define a local class LCL_PROG1_HELPER.
I have a second program ZPROG2_TEST where I'd like to define a variable reference to this class.
Isn't there a syntactic possibility for me to do this?
Or could this be in theory doable with the RTTI classes like CL_ABAP_CLASSDESCR ?
EXTRA
Why I'd like to do this is because I have a custom form ZMM_MEDRUCK that needs to know if the ME32N Document it's printing has been changed but not saved.
I've figures out the exact objects whose properties I need to interogate, but some of them are defined at design time as common interfaces, like IF_SERIALIZABLE_MM, and I need to cast them to the local classes whose instances I know these objects are going to be, like \FUNCTION-POOL=MEGUI\CLASS=LCL_APPLICATION.
I could of course try a dynamic method call and not care about anything, but since i'm here i thought i'd ask this thing first.
You could do it like that.
REPORT ZPROG1_TEST.
INTERFACE lif_prog1_helper.
METHODS:
test.
ENDINTERFACE.
CLASS LCL_PROG1_HELPER DEFINITION.
PUBLIC SECTION.
INTERFACES:
lif_prog1_helper.
ALIASES:
test FOR lif_prog1_helper~test.
ENDCLASS.
CLASS LCL_PROG1_HELPER IMPLEMENTATION.
METHOD test.
WRITE / sy-repid.
ENDMETHOD.
ENDCLASS.
REPORT ZPROG2_TEST.
DATA: g_test TYPE REF TO object.
START-OF-SELECTION.
CREATE OBJECT g_test TYPE ('\PROGRAM=ZPROG1_TEST\CLASS=LCL_PROG1_HELPER').
CALL METHOD g_test->('TEST').
CALL METHOD g_test->('LIF_PROG1_HELPER~TEST').
As far as I know, this is not possible. Accessing the local class dynamically is easy (well, relatively easy), but referring to it statically - not as far as I know. You'll probably have to call the methods dynamically.

ABAP Objects - access message class of a class?

In the header information of an ABAP Objects class, I can enter a message class to use with the MESSAGE statement. This works like the MESSAGE-ID statement of a report or a function pool. Since I can't find the message class I entered in the header data anywhere in the generated sections, I assume that it's generated into the top-level CLASS-POOL statement somewhere.
For some libraries (for examples, the BAL application logging), it's necessary to specify the message class using a variable or a method parameter. Up to now, I've defined a constant that specified the message class and used that constant. I'm wondering if it's possible to access the message class specified in the header data in some other way so that I can get rid of that redundant variable.
Has anyone found a way to do so?
EDIT: The new way should be easier than the old one - I'm not crazy enough to add a CLASS-CONSTRUCTOR and perform some database access or SEO_* function calls just to get rid of that constant.
I think you need a CLASS-CONSTRUCTOR to set a class attribute with the message class.
The MESSAGE statement with INTO clause has the side effect of setting the SY- system variables. So you could put into your CLASS-CONSTRUCTOR something like:
DATA: lf_dummy TYPE string.
MESSAGE s999 INTO lf_dummy.
af_msgid = sy-msgid.
You could use the class builder API:
data the_class type ref to cl_oo_class.
create object the_class
exporting
clsname = `ZCL_SOMECLASS`.
data message_class type arbgb.
message_class = the_class->class-msg_id.
I haven't come across any syntax to do what you ask. For the reasons I outline below, I could believe that SAP never saw a need to include such functionality.
In my experience, the message class is an attribute of the message, not of the object that raises it, so it should be kept together with the type, number, and variables of the message. For example if my object is returning the number of an error, it should be returning the id (class) as well.
In this light I cannot see a reason why you would ever need to know the message-class assigned to an ABAP-OO class, you would only ever need to know the message-class of the messages returned by the ABAP-OO class.
The way I usually manage this is to raise my messages into a dummy field, and then use a subroutine to populate the contents of the sy-msg* fields into a BAPIRETURN structure. Then I return this BAPIRETURN structure to the caller. This way the type, id, number, and variables of the message are all kept together.

Object methods and stats - the best object oriented design approach question

I need to write some instance method, something like this (code in ruby):
def foo_bar(param)
foo(param)
if some_condition
do_bar(param)
else
do_baz(param)
end
end
Method foo_bar is a public api.
But I think, param variable here appears too many times. Maybe it would be better to create an private instance variable and use it in foo, do_bar and do_baz method? Like here: (#param is an instance variable in ruby, it can be initialized any time)
def foo_bar(param)
#param = param
foo
if some_condition
do_bar
else
do_baz
end
end
Which code is better? And why?
Is param replacing part of the state of the object?
If param is not changing the object state then it would be wrong to introduce non-obvious coupling between these methods as a convenience.
If param is altering the state of the object then it may still be bad practice to have a public api altering the state - much better to have a single private method responsible for checking and changing the state.
If param is directly setting the state of the object then I would change the instance variable here but only after checking that the new state is not inconsistent
The first version should be preferred for a couple of reasons. First, it makes testing much easier as each method is independent of other state. To test the do_bar method, simply create an instance of its containing class and invoke the method with various parameters. If you chose the second version of code, you'd have to make sure that the object had all the proper instance variables set before invoking the method. This tightly couples the test code with the object and results in broken test cases or, even worse, testcases that should no longer pass, but still do since they haven't been updated to match how the object now works.
The second reason to prefer the first version of code is that it is a more functional style and facilitates easier reuse. Say that another module or lambda function implements do_bar better than the current one. It won't have been coded to assume some parent class with a certain named instance variable. To be reusable, it will have expected any variables to be passed in as parameters.
The functional approach is the much better approach ... even in object oriented languages.
If you do not need param outside of the foo_bar method the first version is better. It is more obvious what information is being passed around and you are keeping it more thread friendly.
And I also agree with Mladen in the comment above: don't add something to the object state that doesn't belong there.

ABAP create object

Below is a code snippet that is creating object.
Form userexit_save_document_prepare.
data: /bks/exitmanager type ref to /bks/exit_manager.
create object /bks/exitmanager
exporting main_prog = 'SAPMV45A'
exit_form = 'USEREXIT_SAVE_DOCUMENT_PREPARE'.
include /bks/exitman.
ENDFORM.
I got this from the documentation
For performance reasons, the parameters "main_prog" and "exit_form" should be filled, in the case of userexits, which are performed very often like "user_field_modification" in "SAPMV45A" which is called for every single screen-field.
1) What happened exactly behind when create object /bks/exitmanager is called? memory allocated for the object etc?
2) Why for performance reasons the exporting parameters of create object needs to be filled?
I'm not 100% sure, but here is my best guess:
an object called /bks/exitmanager is constructed (which is an oject of the class /bks/exit_manager or more specific a reference/"pointer" to an object of this class) .. the required memory allocated etc., but also the "constructor" code is called (probably sets some instance variables as passed to the call).
If you're explicitly passing these parameters, they don't have to be "calculated" at run-time (e.g. by looking at the call stack). This should save some time, especially if it would have to be done quite often (as described in the documentation).
It would help to see what /bks/exit_manager actually is, and a brief explanation of what you are trying to accomplish.
Expanding on what IronGoofy wrote:
data: /bks/exitmanager type ref to /bks/exit_manager
This creates a reference pointer in the ABAP memory of your program, much like a field symbol. Also it must be already delared. If it is in the include, you need to move the include.
create object /bks/exitmanager
exporting main_prog = 'SAPMV45A'
exit_form = 'USEREXIT_SAVE_DOCUMENT_PREPARE'.
This creates an object instance based on the declared class, and assigns it to the referance pointer. It does this by calling the constructor method first.
Only by examing /bks/exit_manager will you find out exactly what you need to export.
It's impossible to tell what's going on and why the parameters should be passed without taking a look at the constructor of /BKS/EXIT_MANAGER. It's a common pattern though to keep a buffer of settings (think of a static hashed table with the key being the parameters and the value holding whatever is complicated and time-consuming to fetch). In this case, I would have expected a protected constructor that cannot be accessed directly, but only using a static factory method that uses a hashed table to keep the references of the exit handler itself - optimally using weak references...

Error using WCF and DataContractSerializer

I have a fairly complex object model that I'm trying to serialize using WCF. I'm running into a problem where I can create a new instance on the server and return it to the client, then trying to pass that same object back or even serialize it using the DataContractSerializer throws an exception.
Test method Server.Service.Test.SerializationTest.TestFilingSerialization threw exception: System.Runtime.Serialization.SerializationException: There was an error deserializing the object of type MyNameSpace.MyObject. No set method for property '' in type ''
It's not giving me any info on a setter I'm supposedly missing, even though I've tried looking through the inheritance hierarchy for missing setters, I can't seem to get passed this. MyObject is a type of property on the object I'm trying to serialize, here's the funny part. In the setter for that property, I have code that looks like this:
set
{
_backingField = value;
_backingField.IsDirtyManager.SetIsDirty();
NotifyPropertyChanged("MyProperty");
if (!ContainsType(_backingField.GetType()))
{
Aggregates.Add(_backingField);
}
}
If I comment out the Aggregates.Add it goes onto the next property and throws the same exception there, the kicker is, it get's through other properties with the same code, before it hits this one and dies, so I don't know what the problem could be.
Anyone have experience where the real error is, because the Property name and Type are not filled out in the exception so it seems like the error has to be something else. If I just create a new instance on the client I can deserialize and serialize no problems, so there's gotta be something I'm missing here. Any ideas on what to look for?
EDIT
I am literally doing only this:
Create instance
Serialize
De-serialize
Re-serialize
Die here
I am assuming that the "Aggregates" is a list in your class.
If your class constructor does not create an Aggregates list, then it is null when you try to add items to it.
This does not match the error you are getting, but worth checking.
EDIT
In Visual Studio go into "Tools" -> "Options" -> "Debugging" -> "General" uncheck the option "Enable Just My Code". Then run it again, you may get a better error message.
Ok, figured it out. The last developer had set the Order property on the DataMember attribute. It was the property with the order before the property in the error message that was causing the problems. There were a couple read-only properties that I missed in that class.
You might see this if your setter is protected or private. If it's not marked public the serializer will not be able to set it. How do you have your Aggregates collection exposed?