Runtime error when using a parameter's methods - openedge

I'm currently experiencing an error when trying to use a parameter object's methods.
What I'm trying to do:
USING class.Bar.
CLASS class.Foo SERIALIZABLE INHERITS Progress.Lang.Object:
DEFINE PRIVATE VARIABLE cRrk_ID AS CHARACTER NO-UNDO.
CONSTRUCTOR PUBLIC Foo(INPUT objBar AS Bar):
THIS-OBJECT:cRrk_ID = objBar:getRrk_ID(). //Runtime Error: Invalid Handle (3135)
END.
END.
CLASS class.Bar SERIALIZABLE INHERITS Progress.Lang.Object:
DEFINE PRIVATE VARIABLE cRrk_ID AS CHARACTER NO-UNDO.
CONSTRUCTOR PUBLIC Bar(INPUT pcRrk_ID AS CHARACTER):
THIS-OBJECT:cRrk_ID = pcRrk_ID.
END.
METHOD PUBLIC CHARACTER getRrk_ID():
RETURN THIS-OBJECT:cRrk_ID.
END METHOD.
END.
Can someone explain why I can't use an Object's method when it's a parameter?

You need to NEW class.Bar first in class.Foo's constructor.
CONSTRUCTOR PUBLIC Foo(INPUT objBar AS Bar):
objBar = NEW class.Bar () .
THIS-OBJECT:cRrk_ID = objBar:getRrk_ID(). //Runtime Error: Invalid Handle (3135)
END.

You can use but create Bar object and send to Foo's constructor:
DEFINE VARIABLE objBar AS "class.Bar" NO-UNDO.
objBar = NEW "class.Bar"("hi").
DEF VARIABLE objFoo AS "class.Foo" NO-UNDO.
objFoo = NEW "class.Foo"(objBar).

Related

How to call Kotlin companion factory method using callBy()?

I have code accepts a class as a parameter and prepares data to call either the constructor for that class of a companion object factory method if the factory method is present.
All works fine when calling the constructor, but I get the error
java.lang.IllegalArgumentException: No argument provided for a required parameter: instance of fun nz.salect.objjson.JVMTest.StudentWithFactory.Companion.fromJson(kotlin.String, kotlin.Int): nz.salect.objjson.JVMTest.StudentWithFactory
when calling the factory method. The factory method in question:
data class StudentWithFactory(val name: String, val years: Int=0) {
companion object {
fun fromJson(name: String="", age: Int = 0):StudentWithFactory {
return StudentWithFactory(name, age)
}
}
}
has no required parameters, unless there is some hidden parameter. Any ideas?
In fact, I reverted removing the parameters completely from fromJson and directly calling the companion method using ::fromJson.callby(emptyMap()). Same error.
It is clear that companion methods need at least one additional parameter. Perhaps the class? Or the companion object?
How can I specify the needed parameter(s)?
The function building up the callBy() is supplied a class (or finds the class from a supplied class) and json names and values.
var funk:KFunction<*>?=null
val companionFuncs=cls.companionObject?.declaredMemberFunctions
if(companionFuncs?.size ?:0 >0){
companionFuncs?.forEach {
if(it.name == "fromJson") funk=it
}
}
val cons:KFunction<T> = if(funk != null)
funk as KFunction<T>
else
cls.primaryConstructor ?: throw IllegalArgumentException("no primary constructor ${cls.simpleName}")
val valuesMap = cons.parameters.filter{it.name in vals}
.associateBy(
{it},
{generateValue(it)}
)
val data = cons.callBy(valuesMap) //as T
return data
In addition to my short answer, a more technical explanation:
Yes, there actually is a hidden parameter and you can see it (for example), if you take a look at the decompiled (to Java) bytecode:
public final class StudentWithFactory {
// ...
public static final class Companion {
// ...
#NotNull
public static StudentWithFactory fromJson$default(StudentWithFactory.Companion var0, String var1, int var2, int var3, Object var4) {
// ...
return var0.fromJson(var1, var2);
}
// ...
}
}
The first parameter (var0) is actually an instance of the companion object. var1 (name) and var2 (age) are the parameters you declared. var3 is a bitmask for determining if explicit values have been passed or if the default ones should be used*. I honestly don't know what var4 is for. It is unused in the Java code. But the imported part is that you only need to worry about var0, var1 and var2 if you want to invoke the function.
So, in the end the non-static version of fromJson* is actually invoked on the instance of the companion object:
var0.fromJson(var1, var2)
*left code out for simplicity
You can use the parameters property to determine how much parameters you have to pass to the function/constructor.
If you call
val paramsConstr = StudentWithFactory::class.primaryConstructor?.parameters
paramsConstr will be of size two as expected, but if you call
val paramsFunc = ::fromJson.parameters
paramsFunc will be of size three. The first element corresponds to the instance of the companion object. So, thats the list of parameters you need to provide.
You can invoke the fromJson like this:
// not using any default parameters
::fromJson.callBy(mapOf(
paramsFunc[0] to StudentWithFactory::class.companionObjectInstance,
paramsFunc[1] to "Hello",
paramsFunc[2] to 30
))
// using only the default parameter for "name"
::fromJson.callBy(mapOf(
paramsFunc[0] to StudentWithFactory::class.companionObjectInstance,
paramsFunc[2] to 30
))

Progress OpenEdge passing a dataset as parameter looses values

I am trying to pass a dataset as a parameter to a class, but the dataset keeps loosing it's values.
The idea is to put a customer number in the dataset, pass the dataset to the server and let the server fill the dataset with all the customer information and then pass it back to the client.
First calling procedure
This is a unittest procedure calling the ServiceInterface in the server.
USING OpenEdge.Core.Assert.
BLOCK-LEVEL ON ERROR UNDO, THROW.
{USS/Common/Invoice/Include/dsInvoice.i}
DEFINE VARIABLE hProc AS HANDLE NO-UNDO.
RUN USS/Server/Invoice/ServiceInterfaces.p PERSISTENT SET hProc.
TEMP-TABLE ttInvoice:TRACKING-CHANGES = TRUE.
ttInvoice.CustomerNr = CustomerNr.
TEMP-TABLE ttInvoice:TRACKING-CHANGES = FALSE.
RUN UpdateCustomer IN hProc(INPUT CustomerNr, INPUT-OUTPUT DATASET dsInvoice BY-VALUE).
Assert:Equals("MIDDELLANDBAAN 1 B", ttInvoice.DeliveryStreet).
DELETE PROCEDURE hProc.
Service interface on the server
At this moment the dataset still contains all the values. These values are passed to a Business Entity where other values should be added.
PROCEDURE UpdateCustomer:
DEFINE INPUT PARAMETER CustomerNr AS INT.
DEFINE INPUT-OUTPUT PARAMETER DATASET-HANDLE phdsInvoice.
USS.Server.Invoice.BusinessEntity.InvoiceEntity:Instance:UpdateCustomer(INPUT CustomerNr, INPUT-OUTPUT DATASET dsInvoice BY-REFERENCE).
RETURN.
END PROCEDURE.
Business entity
The Business Entity is a singleton, containing an UpdateCustomer method.
When the dataset is passed to this method, it is completely empty.
USING Progress.Lang.*.
USING USS.Common.Interfaces.IBusinessEntity.
USING USS.Server.Invoice.DataAccess.InvoiceBE-DA.
BLOCK-LEVEL ON ERROR UNDO, THROW.
CLASS USS.Server.Invoice.BusinessEntity.InvoiceEntity IMPLEMENTS IBusinessEntity:
{ USS\Common\Invoice\Include\dsInvoice.i &CLassAccess = "private" }
DEFINE PRIVATE VARIABLE InvoiceDA AS InvoiceBE-DA NO-UNDO.
DEFINE PRIVATE VARIABLE hDSEventHandlers AS HANDLE NO-UNDO.
DEFINE PUBLIC STATIC PROPERTY Instance AS USS.Server.Invoice.BusinessEntity.InvoiceEntity
GET.
PRIVATE SET.
CONSTRUCTOR STATIC InvoiceEntity ():
USS.Server.Invoice.BusinessEntity.InvoiceEntity:Instance = NEW USS.Server.Invoice.BusinessEntity.InvoiceEntity().
END CONSTRUCTOR.
CONSTRUCTOR PUBLIC InvoiceEntity ():
SUPER().
InvoiceDA = NEW InvoiceBE-DA().
END CONSTRUCTOR.
METHOD PUBLIC VOID UpdateCustomer(INPUT pCustomerNr AS INT, INPUT-OUTPUT DATASET dsInvoice ):
DEF VAR hUpdateCustomerService AS HANDLE NO-UNDO.
RUN USS/Server/Invoice/Services/UpdateCustomer.p PERSISTENT SET hUpdateCustomerService.
RUN UpdateCustomer IN hUpdateCustomerService (INPUT pCustomerNr, INPUT-OUTPUT DATASET dsInvoice BY-REFERENCE).
RETURN.
END METHOD.
END CLASS.
I have been working on this for a while now and I hope someone can help me figure this one out.
Yes, as Tim mentioned, you use 2 different datasets in internal procedure UpdateCustomer in ServiceInterfaces.p.
You can change the PARAMETER DATASET-HANDLE to:
DEFINE INPUT-OUTPUT PARAMETER DATASET FOR dsSelectionList.

modify groovy trait private field

In my unit tests I usually use reflection to manually inject a mock to the tested class' private field:
static void setFieldValue(Object instance, String fieldName, Object fieldValue, Class instanceClass) {
def field = instanceClass.getDeclaredField(fieldName)
field.accessible = true
field.set(instance, fieldValue)
}
Where instanceClass is the class/superclass, where the class is actually declared. How can I make it work or achieve same result for a private field being declared on a groovy trait?
My IDE helped me - just use the # attribute access notation, where the fieldname is package_dots_replaced_with_underscore_TraitName__fieldName, e.g.
testee.#pl_kamilroman_DeleteEntityBean__messages

why does the compiler complain about missing ctor of WebSocketHandler?

I'm trying to use websocket in my project.
to do so, I installed the package Microsoft Asp.Net SignalR, which consists of WebSocketHandler abstract class.
i defined a class inheriting WebSocketHandler, but then the compiler complains:
'Microsoft.AspNet.SignalR.WebSockets.WebSocketHandler' does not contain a constructor that takes 0 arguments'.
It seems wierd to me, because the definitioin of WebSocketHandler ctor gets a nullable value, which means the ctor could get no parameter,
the definition looks like this:
protected WebSocketHandler(int? maxIncomingMessageSize);
can anybody tell me what the problem is?
thanks.
It seems wierd to me, because the definitioin of WebSocketHandler ctor gets a nullable value, which means the ctor could get no parameter
No, it doesn't. There's a big difference between receiving a null value for a nullable type, and not receiving a value at all.
If the parameter were optional, that would be a different matter - but it's not. You have to supply an argument convertible to int? in the call. If you want to provide the null value for int?, do so:
var handler = new WebSocketHandler(null);
Or if you want to avoid accidentally using any other single-parameter constructor definitions which may be applicable with a null literal as the argument, you could use:
var handler = new WebSocketHandler((int?) null);
Or:
var handler = new WebSocketHandler(default(int?));
protected member is accessible by derived class instances and there's nothing special about it. Nothing special in the class itself, either # WebSocketHandler.cs.
It just mens you need to pass in a nullable type, it does not mean it can't get any arguments.
int? maxIncomingMessageSize = 0;
var socket = new WebSocketHandler(maxIncomingMessageSize);
In your derived class you could/should define a "constructor that takes 0 arguments".
public class MyHandler : WebSocketHandler
{
// not mandatory
public MyHandler()
:this(null)
{}
// mandatory
public MyHandler(int? maxIncomingMessageSize)
:base(maxIncomingMessageSize)
{}
}

Entity Framework: Metadata when Entity Name is Same as Property?

I have a EDM with a entity "Extensions" - within this object is the property extension. I've wired up all the other columns just fine, but this one refuses to wire up. I'm guessing because the entity and the property share the same name?
Here is my code, the extensions doesn't work, the prefix does work:
Imports System.Web.DynamicData
Imports System.ComponentModel.DataAnnotations
<MetadataType(GetType(ExtensionsMetaData))> _
Partial Public Class Extensions
End Class
Public Class ExtensionsMetaData
Private _phones_extensions As Object
Private _prefix As Object
Private _did_flag As Object
Private _len As Object
Private _sfc_id As Object
Private _name_display As Object
Private _floor As Object
Private _room As Object
Private _phones_departments As Object
Private _phones_buildings As Object
Private _phones_phones As Object
Private _phones_restriction_classes As Object
Private _phones_tens As Object
<DisplayName("Extension")> _
Public Property extensions() As Object
Get
Return _phones_extensions
End Get
Set(ByVal value As Object)
_phones_extensions = value
End Set
End Property
<DisplayName("Prefix")> _
Public Property prefix As Object
Get
Return _prefix
End Get
Set(ByVal value As Object)
_prefix = value
End Set
End Property
End Class
How can I get this code to work? I've looked all through my data model and it looks like the name should be Extensions!
The error I am receiving is: The associated metadata type for type 'phoneDBentities.Extensions' contains the following unknown properties or fields: extensions. Please make sure that the names of these members match the names of the properties on the main type.
This is a limitation of EF's "convention over configuration" feature.
Here's a related question: Entity Framework Mapping Oddity - member names cannot be the same as their enclosing type
The easiest way to fix the problem would be to rename the property to "PhoneExtension."

Resources