I'm trying to create a bidirectional one-to-many relationship between Foo and Bar domains in GORM.
Here's what I have so far:
class Bar {
static belongsTo = [foo: Foo]
}
class Foo {
Set bars = []
static hasMany = [bars: Bar]
}
The problem that I'm having is when I go to use the relationship methods, they don't seem to behave the way that I think they should. For example, you would think a statement like "foo.bars.add(bar)" would also set the foo field on the bar argument. But when I call "bar.foo.id" I'm told that the foo field is null. I can fix that problem if I use "bar.foo = foo" instead of "foo.bars.add(bar)". Unfortunately, when I call "foo.bars.size()" it tells me that it is 0.
To get a clearer picture of what I'm talking about, here are my tests:
def testFoo() {
def foo = new Foo()
def bar = new Bar()
foo.bars.add(bar)
println "foo.bars.size() = ${foo.bars.size()}"
println "bar.id = ${bar.id}"
for(def xbar : foo.bars) {
println "bar.id = ${xbar.id}"
}
println "foo.id = ${foo.id}"
println "bar.foo.id = ${bar?.foo?.id}" // <- is null
}
def testBar() {
def foo = new Foo()
def bar = new Bar()
bar.foo = foo
println "foo.bars.size() = ${foo.bars.size()}" // <- is 0
println "bar.id = ${bar.id}"
for(def xbar : foo.bars) {
println "bar.id = ${xbar.id}"
}
println "foo.id = ${foo.id}"
println "bar.foo.id = ${bar?.foo?.id}"
}
What am I doing wrong?
Note: I'm running this through an integration test. I've also found that "foo.addToBars(bar)" works the way that I think "foo.bars.add(bar)" and "bar.foo = foo" should work.
Update Here's a quick hack I did that does what I want (using Hibernate and JPA):
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import stuff.Foo;
public class MyList<Bar> extends LinkedList {
private Foo foo;
public MyList(Foo foo) {
this.foo = foo;
}
#Override
public boolean add(Object obj) {
boolean result = super.add(obj);
try {
Method barMethod = obj.getClass().getDeclaredMethod("setFoo", Foo.class);
barMethod.invoke(obj, foo);
}
catch(NoSuchMethodException noSuchMethod) {
noSuchMethod.printStackTrace();
}
catch(InvocationTargetException invocationTarget) {
invocationTarget.printStackTrace();
}
catch(IllegalAccessException illegalAccess) {
illegalAccess.printStackTrace();
}
return result;
}
}
If you read the documentation, you'll learn that, as you found out but are still questioning, the correct way to add items to a collection so they are persisted correctly is to use the addTo* methods.
So in your case, when you said that using addToBars worked, that's the right way to do this. That said, there are some performance hits you take with that. Another way is to do:
bar.foo = foo
bar.save()
The downside is that foo will not contain bar in its existing Set. You'd have to pull it from the database again. It's a bit of a give and take and you just use the best method for your situation.
Related
I am new to spock.I have created mock object in normal class its works fine. But when we have inheritance like structure as below then I can't able to mock the things properly its gives error (null pointer). Any one have idea how we can do it in spock.
Class Parent{
Third getThird(){
return third;
}
}
Class Child extend Parent{
Object method1(){
String msg=getThird().someMethod(); // need to mock this line
return object;
}
}
given:
Third third=Mock()
Child child=new Child()
child.getThird(false) >> third
third.someMethod() >> "xyz"
when :
Object object=child.method1()
then:
//comparing the things
Can you try this?:
given:
def third = Mock(Third)
Child.metaClass.getThird = {
third
}
when :
Object object=child.method1()
then:
1 * thirdMocked.someMethod() >> "xyz"
and:
//comparing the things
cleanup:
Child.metaClass = null
you can mock classes in Spock like any interfaces :
given:
def thirdMock = Mock(Third) {
someMethod() >> "xyz"
}
def child = Mock(Child) {
third >> thirdMock
}
when :
def object = child.method1()
then:
//comparing the things
however, it's usualy a symptom of a code not really testable. in your case, you should probably make 'third' injectable, and then inject a mock.
I want to override a method definition in Grails. I am trying to use Groovy metaprogramming as the class which I want to override belongs to a framework.
Below is the original class.
class SpringSocialSimpleSignInAdapter implements SignInAdapter {
private RequestCache requestCache
SpringSocialSimpleSignInAdapter(RequestCache requestCache) {
this.requestCache = requestCache;
}
String signIn(String localUserId, Connection<?> connection, NativeWebRequest request) {
SignInUtils.signin localUserId
extractOriginalUrl request
}
}
I am trying to override like below
SpringSocialSimpleSignInAdapter.metaClass.signIn = {java.lang.String str, org.springframework.social.connect.Connection conn, org.springframework.web.context.request.NativeWebRequest webreq ->
println 'coming here....' // my implementation here
return 'something'
}
But for some reason overriding is not hapening. I am not able to figure it out. Any help would be greatly appretiated.
Thanks
Yeah, seems like that bug. I don't know your whole scenario, but anyway, here's a small workaround i made:
In your class definition, you don't implement the interface
You create your object and do your metamagic
Use groovy coercion to make it act as the interface and then you can pass it around
Here is a small script i made using JIRA bug to prove it:
interface I {
def doIt()
}
class T /*implements I*/ {
def doIt() { true }
}
def t = new T()
assert t.doIt()
t.metaClass.doIt = { -> false }
// here the coercion happens and the assertion works fine
def i = t as I
assert !i.doIt()
assert !t.doIt()
// here the polymorphism happens fine
def iOnlyAcceptInterface(I i) { assert !i.doIt() }
iOnlyAcceptInterface(i)
I have piece of code as follows
def revisedSections=sections.collect{sectionObj->
sectionObj.questionCategories=sectionObj.questionCategories.collect{qCat->
def flag=false
this.questionSet.questions = this.questionSet.questions.collect{qObj->
if(qCat.category == qObj.questionCategory.category){
qCat.questions.add(qObj)
//this.questionSet.questions.remove(qObj)
flag=true
}
qObj
}
if(flag){
qCat
}
}
sectionObj
}
log.debug('revisedSections'+revisedSections)
this.metaClass.getSectionsData={-> revisedSections }
log.debug 'this.sectionsData '+this.sectionsData
I want to add sectionsData property to the instance and then convert the instance to json
but i am not able to access the dynamically added property with this code, is there something i am missing ?
You can use mixins to accomplish what you're looking for. Something like the following is native and acceptable Groovy:
class RevisedSection {
String sectionData
}
class Section {
String name
}
Section.mixin RevisedSection
def section = new Section(sectionData: "Data", name: "Section Name")
assert section.sectionData == "Data"
Hope this helps!
If I understand what you are trying to achieve correctly, it is easily feasible with meta programming, and it should work.
Without information about the context of your code I can only guess at the base class of your object etc, so here's some code run in the groovy console, which works perfectly
class D {
int someValue
def init() {
this.metaClass.getSomeString={->someValue as String}
}
}
def d=new D()
d.init()
d.someValue=76
println d.someString
The result is of course the string '76' being printed to the console.
Another suggestion, with a statically compiled getter:
class D {
private Closure computation
int someValue
def init() {
this.computation={someValue}
}
String getSomeString(){
computation() as String
}
}
I would like to map some actions in a child class to their super class, but I cannot figure it out. Example below...
abstract class A {
abstract def foo()
def aAction1 = {
// do something
render(view: '/someView')
}
def aAction2 = {
SomeObject someObject ->
// do something
render(view: '/someView2')
}
}
class B extents A {
def foo() { return "Hello World" }
# map to parent action
# works fine
def jump = super.&aAction1
# doesnt work ... Why? and can I make it work?
def swim = { SomeObject someObject ->
super.aAction2(someObject)
}
}
Any ideas on this one? Thanks.
So it turns out it didnt work because the parameters were slightly different. It does seem to work as expected. If you are having issues with this, make sure that the parameters for any inherited classes are exactly the same as the parent.
Given this relationship:
class A {
String name
static hasMany = [b:B]
}
class B {
String name
static belongsTo = [a:A]
}
I have an record b that I want to save. I've already discovered via working Grails reflection (omitted in the code example below) that it needs to be an instance of class B. Beyond that, record b only knows:
it has a relation "a"
relation "a"'s key
Since it's a dynamic case, we do not know and must discover:
relation "a" is to an instance of class A (so we can call A.find(a's key))
the "other side" of the relation - class A's perspective - is relation "b" (so we can call .addToB(b))
So how do I save b to the database? Here's how I'm doing it:
class AssocTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
// I don't know this part, but it's in the DB
def a = new A(name:"al")
a.save()
}
void testAssociation() {
// I want to create a new B such that name="bob"
// I also had to discover "class B" using (working) Grails reflection
// but omitted it for this example.
def b = new B(name:"bob")
// ... and the relation is as "given" below
def given = [a:[name:"al"]]
// So I need to call A.find([name:"al"]).addToB(b). But "A" and
// "addToB" are unknown so need to be found via reflection
def gdc = new DefaultGrailsDomainClass(B)
given.each { give ->
def prop = gdc.getPropertyByName(give.key)
if (prop.isAssociation() && !prop.isOwningSide()) {
println "I want to use otherSide, but it's ${prop.otherSide}"
def os = reallyGetOtherSide(B, give)
def object = os.parent.find(
os.parent.newInstance(give.value))
object."${os.method}"(b)
}
}
def bFound = B.findByName("bob")
assertEquals "al", bFound.a.name
}
def reallyGetOtherSide(clazz, relation) {
def parent=clazz.belongsTo[relation.key]
def addTo=parent.hasMany.find { (clazz == it.value) }.key
[parent:parent, method:"addTo${addTo.capitalize()}"]
}
}
...with otherSide returning null, unfortunately. This can't be the best way to do this, can it?
If I understood you correctly, You can refer to these docs here. You can try the following:
`new A(name:"Gatwick")
.addToB(new B(name:"BA3430"))
.addToB(new B(name:"EZ0938"))
.save()`