Invoking methods with drools - field

This is a beginner question with drools. I have looked over the doc and code examples and still can't figure out what should be very simple to do.
In my when statement, I have a variable $servletRequest of type HttpServletRequest. I know how to invoke a getter that doesn't take any input parameter, such as getCharacterEncoding. I.e., this:
when
...
HttpServletRequest( characterEncoding == "xxx" ) from $servletRequest
then
works. However, I can't figure out how to invoke a getter that requires an input argument. I.e., I would like to access the header "X-REQUESTED-PAGE" from my request, but the following doesn't work:
when
...
HttpServletRequest( header["X-REQUESTED-PAGE"] == "xxx" ) from $servletRequest
then
It gives me an exception:
org.drools.RuntimeDroolsException: Exception executing predicate header["X-REQUESTED-PAGE"] == "xxx"
at org.drools.rule.PredicateConstraint.isAllowed(PredicateConstraint.java:279)
...
What am I missing?

In Drools 5.5, this should work:
when
...
HttpServletRequest( getHeader("X-REQUESTED-PAGE").equals("xxx") ) from $servletRequest
then

Related

`Error: request to generate code for .compileTime proc`

I have a small helper proc that is supposed to tell me at compile-time whether a type is an object-type or not.
func isObject*[T](val: typedesc[T]): bool {.compileTime.} = T is (object or ref object)
However, when I call this proc with a simple echo to see whether it works, I receive an error:
type A = object
echo isObject(A)
Error: request to generate code for .compileTime proc: isObject
Why is that? It should be perfectly valid to just call this, isObject should just compile to true and in the end what's written there is echo true, why does this cause this cryptic error?
The problem here is that runtime code (The echo call) is trying to work with a compiletime proc.
That is not valid, as the compiler would not replace the function-call with its result, but try to actually call the function at runtime instead. The compiler knows this is invalid behaviour and thus prohibits it by throwing an error, albeit one that isn't that useful.
The only way this can be allowed is if you store the result of the compile-time proc in a compile-time variable, aka a const. These are allowed to be used at runtime.
So the calling code would look more like this instead:
type A = object
const x = isObject(A)
echo x
EDIT:
As Elegantbeef pointed out on nim's discord:
Another alternative is to just do what I thought would happen initially and have that isObject(A) call evaluate fully at compile-time, so that at runtime it goes away and all that's left is it's result, true.
To do so, just use static:
type A = object
echo static(isObject(A))

Matching a method signature with a unknown parameter in a mocked class

I have this method:
Future<Either<Failure, WorkEntity>> updateWorkEntity({int id, String title, TimeType timeType, int times, DateTime executed})
that is being called like this:
repository.updateWorkEntity(id: workEntity.id, executed: DateTime.now())
the id I can control in a test, but the "DateTime.now()" I ofcourse can not. What I tried was this in my test:
when(repository.updateWorkEntity(id: expected.id, executed: any)).thenAnswer((_) async => Right(expected));
to be able to make my mock return a object for my test, by using "any" in the place of the "DateTime.now()", but I get this error:
Invalid argument(s): The "any" argument matcher is used outside of
method stubbing (via when) or verification (via verify or
untilCalled). This is invalid, and results in bad behavior during
the next stubbing or verification.
So I guess I can not use any here, but then how do I get my mock to return an object when I do not control one of the input parameters?
Thank you
Søren
Use executed: anyNamed('executed') instead of executed: any

closure verification override default mocking

I have a method looks like this:
public void save(DbSession session,Wrappe wrapper,Wrappe wrappe){
//...other logic
//save wrapper
wrapper=(Wrapper)session.save(wrapper)
//set wrapper's id into wrappee
wrappee.setWrapperId(wrapper.getId());
//save wrappee
session.save(wrappee);
}
and test code looks like this:
given:
session.save(_) >> wrapperWithGeneratedId
when:
obj.save(session,wrapper,wrappee)
then:"wrapper got saved"
1*session.save(_) >> {Wrapper save ->
diffs(wrapper,saved)==null
}
and:"wrappee"
1*session.save(_) >> {Wrappe saved ->
diffs(wrappee,saved)==null
}
These test code will give an exception:
java.lang.ClassCastException: java.lang.Boolean cannot be cast to com.company.model.Wrapper
If commented verification closure in "then" section,test will pass,so I guess this section
1*session.save(_) >> {Wrapper save ->
diffs(wrapper,saved)==null
}
overrode this mocking:
session.save(_) >> wrapperWithGeneratedId
Is any way do both correctly?
1st. 'and' is syntactic sugar. It's just a way to visually separate code within the same block. Your last two mocks are effectively the same (although since you're testing behaviorally it will still verify that save is called twice.)
2nd. Assuming you want to verify thatdiffs(wrapper,saved)==null, that won't currently happen because it's not a 'base level' evaluation. Anything within then/where/closures/etc needs to be prepended with 'assert ' if you want to evaluate it.
3rd. A then block is scoped to its when block and can override existing mocks; your assumption that your mock was being overwritten is correct.
4th. Is there any reason you don't just include your return value alongside your evaluation?
2 * session.save(_) >> {Wrapper save ->
diffs(wrapper,saved)==null
return wrapperWithGeneratedId
}
5th. Your error is due to your mock returning a boolean (your assertion logic) which Groovy then tries (and fails) to parse into a Wrapper. My assumption for why this is happening is that .save() has a return type of Wrapper. To fix that you will either need to create a boolean constructor for Wrapper, or change your mock to return something Groovy can turn into a Wrapper (how-to in point 4)
Official Stub/Mock/Spy documentation (quite good, worth a read)

Strange behavior of gorm finder

In a controller I have this finder
User.findByEmail('test#test.com')
And works.
Works even if I write
User.findByEmail(null)
But if i write
User.findByEmail(session.email)
and session.email is not defined (ergo is null) it throw exception
groovy.lang.MissingMethodException: No signature of method: myapp.User.findByEmail() is applicable for argument types: () values: []
Is this behavior right?
If i evaluate "session.email" it give me null so I think it must work as it do when I write
User.findByEmail(null)
Even more strange....
If I run this code in groovy console:
import myapp.User
User.findByEmail(null)
It return a user that has null email but if I run the same code a second time it return
groovy.lang.MissingMethodException: No signature of method: myapp.User.findByEmail() is applicable for argument types: () values: []
You can't use standard findBySomething dynamic finders to search for null values, you need to use the findBySomethingIsNull version instead. Try
def user = (session.email ? User.findByEmail(session.email)
: User.findByEmailIsNull())
Note that even if User.findByEmail(null) worked correctly every time, it would not necessarily give you the correct results on all databases as a findBySomething(null) would translate to
WHERE something = null
in the underlying SQL query, and according to the SQL spec null is not equal to anything else (not even to null). You have to use something is null in SQL to match null values, which is what findBySomethingIsNull() translates to.
You could write a static utility method in the User class to gather this check into one place
public static User byOptEmail(val) {
if(val == null) {
return User.findByEmailIsNull()
}
User.findByEmail(val)
}
and then use User.byOptEmail(session.email) in your controllers.
Jeff Brown from grails nabble forum has identified my problem. It's a GORM bug. see jira
More info on this thread
This jira too
I tried with debugger and it looks it should be working, as you write. Maybe the groovy itself is a little bit confused here, try to help it this way:
User.findByEmail( session['email'] )

Grails service - invoking method from controller?

I'm trying to call a method on a grails service from a controller, but it looks like execution is just skipping the method call.
I've tried debugging the application with a breakpoint inside the method but it is never hit.
My service (generated with grails create-service) is:
class FormatterService {
static transactional = false
def formatList (List<Host>, String fmt) {
OutputObject somePOGO = new OutputObject();
(snip)
return somePOGO
}
}
Then on my controller I have:
class HostController {
def formatterService
def getHostsByLabels = {
(snip)
OutputObject o = formatterService.formatList(someHosts,params.format)
(snip)
}
}
When the formatterService.formatList method should be called in the controller, execution simply skips to the next line, no output is printed to the console and breakpoints within the method are not hit. The OutputObject o reference is null afterward.
What is wrong here? It could be a really basic mistake from my part, but I just can't put my finger on it...
To Me it seems a MetaProgramming Disaster..
Well there are 3 Tests to Debug:
_1) first try to do
println formatterService
println formatterService.getClass()
just to check if its injected bean is the desired one, some plugins sometimes inject beans which overrides the default.
_2) Make sure that the method with a name "formatList" is not injected in your services through metaprogramming by any plugin or core code.
How to test this is simple: Just change the name of the method to some Unrealistic One, ex: "formatListabcdewdw" and then call that one. If it works then its method overriden issue.
and if you are more enthusiastic you can see the metaMethods by
println formatterService.metaClass.methods
_3) just try to do "params.format as String" as the last argument in the method call.\
.
Hope any of these helps, please Do let me know of the findings, i am curious to know.. :)
I found the issue. It has to do with the method signature.
Printing out the thrown exception's message, it says:
No signature of method: hms.FormatterService.formatList() is applicable for argument types: (java.util.TreeSet, java.lang.String) values: (...)
Possible solutions: formatList(java.util.List, java.lang.String)
So, a rookie mistake (wanting to pass a TreeSet for a List) aided by weak typing in Groovy... :P
I've changed the method signature to
def formatList ( items, String fmt) {
and call it as
def activeHosts = ...
OutputObject o = formatterService.formatList(activeHosts, params.format as String)
and now it works.

Resources