EasyMock 3.2: Creating an expect() for a method that takes a generic as an argument - easymock

In one of my mocked classes, I need to create an expect for a method with a signature similar to this:
public <T extends Object> T createInitInstance(Class<T> cast)
What I return will differ based on the cast argument. It will be another mocked object, of the type specified by cast. Some of the ways I've tried are:
expect(core.createInitInstance(anyObject(QueryParserPlugin.class))).andReturn(queryPlugin);
and
expect(core.createInitInstance(isA(QueryParserPlugin.class))).andReturn(queryPlugin);
and
expect(core.createInitInstance(isA(Class.class))).andReturn(queryPlugin);
Where queryPlugin is a mock of the class QueryParserPlugin. The first two give a compiler error, saying:
required: Class<T>
found: QueryParserPlugin
The third one compiles, but always returns a null, probably because it's not matching the expect, and the mock was created with createNiceMock.
Any idea how I can correctly specify the parameter?

This ended up being a Java question rather than an EasyMock one, but this is what worked:
expect(core.createInitInstance(isA(QueryParserPlugin.class.getClass()))).andReturn(queryPlugin);

Related

Check if generic is an array with inline function

How can I check if a Generic is an Array using an inline function?
I tried with the following code:
class Mediator {
inline fun <reified C> mediate(string: String): Container<C> {
if (C::class == Int::class) {
//It works
}
else if (C::class == Array::class) {
//It doesn't work!
}
throw IllegalStateException("Yopta")
}
}
But it doesn't work. Maybe because it can be Array<Whatever>?
How can I do it?
Contrary to collections where for example List<String> and List<Int> are internally represented by the same class List, in arrays the type parameter is a part of the type itself. That means Array<String> and Array<Int> are internally represented as different types and as far as I know, they don't have a common super type.
I don't know a pure Kotlin solution to check if a class is an array. It seems to me like an overlook in the design of the reflection API. If you don't mind using the Java reflection, you can do it like this:
else if (C::class.java.isArray) {
Update
There is one interesting fact here. In the Kotlin type system we could consider Array<out Any?> to be a supertype of all arrays. For example, we can upcast to it without an explicit cast operator:
val intArray = arrayOf(1, 2, 3)
val arr: Array<out Any?> = intArray
However, for the reflection API these two types are entirely different:
// false
println(Array<Int>::class.isSubclassOf(Array<out Any?>::class))
I assume this is due to how arrays where implemented in Java. I'm not even sure if it would be technically possible to return true in the code above. Still, it is concerning it provides a different result than the type system at a compile time and it doesn't even produce a warning.
Actual answer that solves the issue here.
Since broot added an actual answer I'll just leave this here as a note as to how we can see that he is right basically.
If we make the call like this:
Mediator().mediate<Array<Int>>("")
Adding a simple check inside the function like this makes it a bit confusing as to why they are not equal.
println(C::class) //class Kotlin.Array
println(Array:class) //class Kotlin.Array
But doing the same for the underlying java class shows that they are not really the same object.
println(C::class.java) //class [Ljava.lang.Integer
println(Array:class.java) //class [Ljava.lang.Object
So changing the statement to:
if(C::class.java == Array<Int>::class.java)
Will make the example work ... for Int only. All other "infinite" possibilities will have to be added manually. Not an issue if you just want to check Array<X> only, but definitely not generic.

Calling Apex method with multiple signatures from LWC

I've noticed some interesting behavior in an LWC that I am building and haven't been able to find much info on the cause. Basically I have an Apex method declared with multiple signatures:
// myMethod with 2 param signature
#AuraEnabled
public static void myMethod(String param1, String param2) {
// I expect this method to be invoked when called from the LWC code shown below
....
}
// myMethod with 3 param signature
#AuraEnabled
public static void myMethod(String param1, String param2, Boolean param3) {
// However this method gets invoked instead
....
}
When I attempt to call myMethod from an LWC, and only pass two parameters into the method, I would expect that the 2 param signature method would be invoked, however what happens is that the 3 param signature method is invoked, and the value of null is passed as the third params value.
runJob({param1, param2}).then(value => ... )
Is this expected behavior? When I call the methods through apex, the correct method is invoked by its signature, however this doesn't seem to be the case when calling the method from an LWC.
Is there a way for me to invoke the myMethod Apex method of the correct signature from an LWC?
Edit:
it will be banned at compile time in Summer'22 release. https://help.salesforce.com/s/articleView?id=release-notes.rn_apex_ValidationForAuraEnabledAnnotation.htm&type=5&release=238
Original:
It's worse than you think. runJob({param2, param1}) will work correctly too. "Correctly" meaning their names matter, not the position!
Your stuff is always passed as an object, not a list of parameters. You could have a helper Apex wrapper class and (assuming all fields are #AuraEnabled) it'll map them correctly. If you have list of parameters - well, a kind of unboxing and type matching happens even before your code is called. If you passed "abc" to a Date variable - a JSON deserialization error is thrown even before your code runs, you have no means to catch it.
https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.apex_wire_method
If the Apex method is overloaded, the choice of what method to call is
non-deterministic (effectively random), and the parameters passed may
cause errors now or in the future. Don't overload #AuraEnabled Apex
methods.
So... pick different names? Or funnel them so the 3-param version looks at the last param and calls 2-param one if needed and the business logic allows it. Generally - keep it simple, leave some comments and good unit tests or 2 months from now poor maintenance guy will struggle.
And (if you use the Apex PMD plugin and/or sfdx scanner) functions with long parameter lists are frowned upon anyway: https://pmd.github.io/latest/pmd_rules_apex_design.html#excessiveparameterlist
See also
https://github.com/trailheadapps/lwc-recipes/issues/196
https://salesforce.stackexchange.com/questions/359728/apex-method-overloading-is-not-working-when-called-from-lwc-javascript-controlle

CakePHP4: Convert or cast Cake\ORM\Entity to actual entity for type hinting

Let's say I have a method that is expecting an Invoice entity as a parameter. So I add the type hint Invoice like so:
public function doThatThing (Invoice $invoiceEntity)
{
// ... operate on $invoiceEntity
}
Unfortunately, when I pass the results of InvoiceTable->get(123), I get the error "TypeError: Argument 1 passed to doThatThing must be an instance of App\Model\Entity\Invoice, instance of Cake\ORM\Entity given..." in my unit tests.
Is there a good way to cast or convert the generic ORM results of ->get() to the specific Entity type that I know it must be?
#greg-schmidt got me looking in the right direction. I'm afraid my question only mentioned the key clue in passing when I said "in my unit tests."
As it turns out, my unit test has a fake invoice table that extends InvoiceTable. My fake does call setTable and setAlias so that it looks like the real table.
But when I call get() on the fake, the call chain bypasses InvoiceTable, lands in ORM/Table, and eventually calls into ORM/Query. When ORM/Table calls the constructor on ORM/Query, it passes $this, which is an instance of my fake, and not of the real, underlying InvoiceTable (setTable and setAlias have no effect at this point). And as #greg-schmidt guessed,
InvoiceTable is almost certainly not your invoice table implementation
My solution will be to have my fake invoice implement its own get() method which will return the response from a real InvoiceTable.

I am getting this error when executing Testng in selenium

Data Provider public java.lang.Object[] as.get() must return either Object[][] or Iterator<Object>[], not class java.lang.Object;
As the documentation says:
The Data Provider method can return one of the following two types:
An array of array of objects (Object[][]) where the first dimension's
size is the number of times the test method will be invoked and the
second dimension size contains an array of objects that must be
compatible with the parameter types of the test method. This is the
cast illustrated by the example above.
An Iterator<Object[]>. The only
difference with Object[][] is that an Iterator lets you create your
test data lazily. TestNG will invoke the iterator and then the test
method with the parameters returned by this iterator one by one. This
is particularly useful if you have a lot of parameter sets to pass to
the method and you don't want to create all of them upfront.
So, I suppose you current data provider method is returning Object instead of one of the 2 supported types.

Scala arrays and parameterized types

I'm trying to define a generic class that takes a parameterized type T and then use the type in an Array definition in the class. I wrote the following which I thought seemed like it should work
class MyClass[T] {
val myarr:Array[T] = new Array[T](10)
}
But the compiler complains with the following
can't find the class manifest for element type T
value newArray is not a member of Null
Anyone know whats going on here and what its not happy about?
The compiler needs to know how to instantiate things of type T. In the traditional Java way of handling generics through type erasure, this cannot reasonably be done; the compiler just says, "Hey, I don't know what T is, so I don't feel so great about allowing you to instantiate a T like that." In Scala, however, there is a word-around for this: manifests. In order to include the manifest for T, just change the first line of that code to
class MyClass[T : Manifest] {
That's it.

Resources