instanceof in Grails - grails

How to determine Class type of Object in collection?
class Human{...}
class Man extends Human{...}
class Women extends Human{...}
def humans = Human.findAll()
humans.each(){ human ->
// ??? , it is not work
if ( human instanceof Man ) { println "Man" }
if ( human instanceof Woman ) { println "Woman" }
}
Thanks a lot,
Tom

Based on your description, I would say you are running into Hibernate proxy objects (ie. class name is: Human_$$javaassist*). Solution would be to use the GORM provided version of insatnceOf. No need to eager fetch or use a different method.
def planet = Planet.get(1)
planet.humans.each(){ human ->
if (human.instanceOf(Man)) { println "is Man"}
if (human.instanceOf(Woman)) { println "is Woman"}
}
Notice the difference human.instanceOf(Man) rather than human instanceof Man. Use the gorm method rather than the java keyword.
You can see this section of the reference documentation for an [explanation][1]. See subsection "Lazy Single-Ended Associations and Proxies"
[1]: http://grails.org/doc/latest/guide/single.html#5.5.2.8 Eager and Lazy Fetching

It looks as if it should work.
A couple random thoughts: are your humans correctly built? Maybe they are really not instances of Man or Woman.
You can do some tests using polymorphism:
class Human{ ...
def speak() { println "Human" }
}
class Man extends Human{ ...
def speak() { println "Man" }
}
class Women extends Human{ ...
def speak() { println "Woman" }
}
def humans = humanService.all()
humans.each(){ human ->
human.speak()
}
If the last line prints "Human Human Human", then the humans are not correctly built, and they are all human instances, instead of Man / Woman. If it shows an error, then they are something else (like nulls or something)
Good luck!

There's nothing wrong with the code above, so my guess is that Human.findAll() is returning an empty collection, which would explain why nothing is being printed. Can you try this code instead?
class Human{...}
class Man extends Human{...}
class Women extends Human{...}
println "You have ${Human.findAll().size()} humans"
If this prints "You have 0 humans", then my guess is correct. If you want to get a list of all instances of Human, then it's probably better to use Human.list() instead of Human.findAll()

in Grails with Hibernate is really problem with instanceof. I have again trouble with it. I find this article:
http://community.jboss.org/wiki/ProxyVisitorPattern
I mean that trouble is appear when your class has some relations.
For example:
def planet = Planet.get(1)
planet.humans.each(){ human ->
//it is not work, see the link above
if (human instanceof Man) { println "is Man"}
if (human instanceof Woman) { println "is Woman"}
}
Tom

thank for your help. I try your test. Method speak() return expected results.
For Man return "Man", for Woman return "Woman".
Your test finished ok, but my trouble is always here.
Maybe I forgot get more information:
This code is from Grails project. I mean that it is not important.
Exactly I use GORM call:
def humans = Human.findAll()
Tomas

Which version of Grails? I just tried this in the Grails 1.2.2 console and it works:
new Woman(name: "Julie").save()
new Woman(name: "Xena").save()
new Woman(name: "Mary").save()
new Man(name: "James").save()
new Man(name: "Tony").save(flush: true)
def people = Human.list()
for (p in people) {
println ">> ${p.name} (${p.getClass()})"
if (p instanceof Man) println "It's a man"
if (p instanceof Woman) println "It's a woman"
}
Perhaps it's an issue that has been fixed?

Related

Add custom information to Spock Global Extension

I have configured Spock Global Extension and static class ErrorListener inside it. Works fine for test errors when I want to catch feature title and errors if they happen. But how can I add some custom information to the listener?
For example I have test that calls some API. In case it fails I want to add request/response body to the listener (and report it later). Obviously I have request/response inside the feature or I can get it. How can I pass this information to the Listener and read later in the handling code?
package org.example
import groovy.json.JsonSlurper
import org.spockframework.runtime.AbstractRunListener
import org.spockframework.runtime.extension.AbstractGlobalExtension
import org.spockframework.runtime.model.ErrorInfo
import org.spockframework.runtime.model.IterationInfo
import org.spockframework.runtime.model.SpecInfo
import spock.lang.Specification
class OpenBrewerySpec extends Specification{
def getBreweryTest(){
def breweryText = new URL('https://api.openbrewerydb.org/breweries/1').text
def breweryJson = new JsonSlurper().parseText(breweryText)
//TODO catch breweryText for test result reporting if it is possible
expect:
breweryJson.country == 'United States'
}
def cleanup() {
specificationContext.currentSpec.listeners
.findAll { it instanceof TestResultExtension.ErrorListener }
.each {
def errorInfo = (it as TestResultExtension.ErrorListener).errorInfo
if (errorInfo)
println "Test failure in feature '${specificationContext.currentIteration.name}', " +
"exception class ${errorInfo.exception.class.simpleName}"
else
println "Test passed in feature '${specificationContext.currentIteration.name}'"
}
}
}
class TestResultExtension extends AbstractGlobalExtension {
#Override
void visitSpec(SpecInfo spec) {
spec.addListener(new ErrorListener())
}
static class ErrorListener extends AbstractRunListener {
ErrorInfo errorInfo
#Override
void beforeIteration(IterationInfo iteration) {
errorInfo = null
}
#Override
void error(ErrorInfo error) {
errorInfo = error
}
}
}
Create file src/test/resources/META-INF/services/org.spockframework.runtime.extension.IGlobalExtension
and place string "org.example.TestResultExtension" there to enable extension.
I am pretty sure you found my solution here. Then you also know that it is designed to know in a cleanup() methods if the test succeeded or failed because otherwise Spock does not make the information available. I do not understand why deliberately omitted that information and posted a fragment instead of the whole method or at least mentioned where your code snippet gets executed. That is not a helpful way of asking a question. Nobody would know except for me because I am the author of this global extension.
So now after having established that you are inside a cleanup() method, I can tell you: The information does not belong into the global extension because in the cleanup() method you have access to information from the test such as fields. Why don't you design your test in such a way that whatever information cleanup() needs it stored in a field as you would normally do without using any global extensions? The latter is only meant to help you establish the error status (passed vs. failed) as such.
BTW, I even doubt if you need additional information in the cleanup() method at all because its purpose it cleaning up, not reporting or logging anything. For that Spock has a reporting system which you can also write extensions for.
Sorry for not being more specific in my answer, but your question is equally unspecific. It is an instance of the XY problem, explaining how you think you should do something instead of explaining what you want to achieve. Your sample code omits important details, e.g. the core test code as such.

Auto alignment of data in Xtext

I had one custom parser rule in which I had defined all my keywords such as _self, _for, _loop etc. Because of this, if I type _s and click Ctrl+ space bar, it shows _self.But what I required is even though I type self or SE, it should auto assign as _self.Is it possible? If so, could anyone please suggest a solution for this. Thanks in advance
There are multiple things to be payed attention to
There needs to be a proposal and only one proposal. Otherwise the user has to select the prosal to be applied and no auto insert takes places
Proposals are created based on the error recovery and so you might not get the proposal you are looking for at all
so lets assume you have a grammar like
Model:
greetings+=Greeting*;
Greeting:
'_self' name=ID '!';
and a model file like
SE
Then the error recovery will work fine an a proposal of "_self" will be added to the list of proposals
Proposals are Filtered based on the current prefix in the model. that would be the place you could start customizing.
e.g. this very naive impl
import org.eclipse.xtext.ui.editor.contentassist.FQNPrefixMatcher;
public class MyPrefixMatcher extends FQNPrefixMatcher {
#Override
public boolean isCandidateMatchingPrefix(String name, String prefix) {
return super.isCandidateMatchingPrefix(name, prefix) || super.isCandidateMatchingPrefix(name, "_" + prefix);
}
}
and dont forget to bind
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
import org.eclipse.xtext.ui.editor.contentassist.PrefixMatcher
import org.xtext.example.mydsl4.ui.contentassist.MyPrefixMatcher
#FinalFieldsConstructor
class MyDslUiModule extends AbstractMyDslUiModule {
override Class<? extends PrefixMatcher> bindPrefixMatcher() {
return MyPrefixMatcher;
}
}
There is another feature that does not use proposals at all but the text that is actually typed and if it recognizes something then can replace it with something else. this feature is called "Auto Edit". The extension point in xtext for this is IAutoEditStrategy / AbstractEditStrategyProvider

Grails saved list not in dbconsole

I am doing this:
class Face {
String name
def ears = []
Nose nose
void addEar(Ear ear){
ears << ear
}
}
class Nose {
String name
}
class Ear {
String name
}
And on Bootstrap.groovy:
def nose = new Nose(name: "Nose")
nose.save()
def leftEar = new Ear(name: "Left ear")
leftEar.save()
def rightEar = new Ear(name: "Right ear")
rightEar.save()
def face = new Face(name: "Face", nose: nose)
face.addEar(leftEar)
face.addEar(rightEar)
face.save()
When I run the app and enter dbconsole to see the tables, face has a reference to its nose and I can read its name "Face", but it has no reference to its ears. How should I save this list so I can access it later?
Or in case it's actually saved somewhere, where? How should I access it?
Take a look at Grails documentation about associations. Focus on 'One to many' and 'Many to many' associations. You can find nice examples on how to declare association (static hasMany property) and add elements to them (addTo* method).

Testing rendered content of a .gsp page in Grails 2.3.8

First time asking here. I'll cut right to the chase. I'm trying to test the rendered view of a controller, and I haven't found any clear way to do it. In particular, what I'm trying to do is test the actual content of the .gsp rendered; namely, if the html page rendered contains a list of items (list, as in a <ul> and <li> tags, for example), or any other content the page should display. Is this possible? Or even a valid approach to test this kind of thing? I tried doing something like this:
The controller:
class ConnectedPairController {
def show(int id) {
//Some logic to populate collections and stuff
render(view:"show.gsp", model:['pqc':cp.getPath(),
'connected':cp.getPage(),
'instance':coll,
'pagesCollection':colPages])
}
The test:
#TestFor(ConnectedPairController)
class ConnectedPairControllerSpec extends Specification {
void "test show"() {
when:
controller.show(4) //4 being the id of the content I want to display
then:
controller.response.text.contains "Some string or html tag the page should display"
}
}
But the text returned is null. Maybe this is how it should be, but is there a way to get the rendered content?
What I found in the documentation is not useful (at least not for what I want to do), since IMHO it only tests trivial stuff, like what .gsp is being rendered, or the content of variables:
#TestFor(SimpleController)
class SimpleControllerSpec extends Specification {
void 'test home'() {
when:
controller.home()
then:
view == '/simple/homePage'
model.title == 'Hello World'
}
}
I hope I'm being clear enough. Thank you for your time.
PS: I'm using Grails 2.3.8. If you need any other information related to the environment and such, please let me know.
The response is not fully rendered in a unit test. response.text will always be null when rendering views.
The purpose of a unit test is to test one unit and mock out everything around it. The view layer is outside that unit.
If you want to test the view, try the GroovyPageUnitTestMixin
Mr. Haki has a good post on how to test views and templates that explains how to test them.
#ColinHarrington Thanks for your answer, and sorry for the delay. I have tried what it says on those websites, but no matter what view (.gsp) I render (like a simple page that just renders the content of a variable), the render method always returns null (not even an empty string).
The controller:
class TestingController {
def index() {
render view: "testing.gsp", model: [test:"Test String"]
}
}
The test:
import grails.test.mixin.TestMixin
import grails.test.mixin.web.GroovyPageUnitTestMixin
import spock.lang.Specification
#TestMixin(GroovyPageUnitTestMixin)
class TestingControllerSpec extends Specification {
def controller
def setup() {
controller = testFor(TestingController)
}
void "test something"() {
when:
controller.index()
then:
render (view:"/testing/testing.gsp", model:model) == "Test String"
}
}
Test result:
test something(webbluefinder.TestingControllerSpec)
|
Condition not satisfied:
render (view:"/testing/testing.gsp", model:model) == "Test String"
| | |
null | false
[test:Test String]
I also tried Mr. Haki's approach, and got the same result.
Do you happen to know why this is happening? Thanks for your time.

getArtefact return NULL for the "Domain"

I am new to Grails and was trying to follow with the examples in "Beginning Groovy and Grails"
When I was trying out the examples, I had the following issue:
domainClass = grailsApplication.getArtefact("Domain", domainClassName)
The domainClass was returning NULL. But when I use the following snippet, I get the correct Class.
if (!domainClass) {
def artefacts = grailsApplication.getArtefacts("Domain")
domainClass = artefacts.find {item ->
item.name == domainClassName
}
}
What is wrong with the first part? Is there anything else that I need to take care of. I downloaded the example code of the book and I haven't seen any other specific changes.
Thanks in Advance!!
Use the full path of the domain class i.e prefix the package.
The first code snippet works too, the domainClassName just needs to be fully qualified name ie packagename.domainclassname
def domainClassName = 'org.abc.Sample'
def domainClazz = grailsApplication.getArtefact('Domain', domainClassName)

Resources