0

I have created a Grails 4.0 application using the VUE profile and am using the JSON Views (http://views.grails.org/latest/#_json_views) and everything works correctly but I haven't found a way to use domain methods in the .gson template

An example that works perfectly fine:

Person.groovy domain class

class Person {

    String firstName
    String lastName

    String fullName(){
        return "$firstName $lastName"
    }
}

PersonController

class PersonController {

    def show(){
      respond Person.get(params.id)
    }

}

/views/person/_person.gson

model {
    Person person
}

json {
    lastName person.lastName
    firstName person.firstName
    //fullName person.fullName() -- this line doesn't compile
}

This is a basic example of what I'm trying to do but I can't get anything like this to compile and I haven't seen in the docs if it's even possible. I also tried calling the method in the domain class "getFullName()" and then in the gson file doing "fullName person.fullName" but that didn't work either.

Is there a way to use the methods of a domain class in the .gson file?

UPDATE: This is an example of the stacktrace log with the getFullName()

[Static type checking] - No such property: fullName for class: Person
 @ line 8, column 8.
       fullName person.fullName
          ^

1 error

    at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:311)
    at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1102)
    at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:645)
    at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:623)
    at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:600)
    at grails.views.ResolvableGroovyTemplateEngine$_createTemplate_closure2.doCall(ResolvableGroovyTemplateEngine.groovy:430)
    ... 71 common frames omitted

And this is an example of it as fullName() method

[Static type checking] - Cannot find matching method Person#fullName(). Please check if the declared type is correct and if the method exists.
 @ line 8, column 8.
       fullName person.fullName()
          ^

1 error
user779643
  • 37
  • 6
  • What does "does not compile" mean? Are there errors or stacktraces to share? – cfrick Aug 20 '19 at 21:21
  • @cfrick Question has been updated with errors from log file – user779643 Aug 20 '19 at 21:39
  • Have you tried using transients yet? Looks to be exactly what you are looking for: http://docs.grails.org/latest/ref/Domain%20Classes/transients.html – Joshua Moore Aug 21 '19 at 12:38
  • @JoshuaMoore transients would not have anything to do with the compilation error. They would be relevant if he had a method in his domain class named `getFullName()`, but that isn't what he/she has. What I would do is have a `getFullName()` method, make `fullName` transient and then in the view reference `person.fullName`, but the reasons that are a better idea than when he/she is doing, doesn't help address the compilation error that the question is asking about. – Jeff Scott Brown Aug 21 '19 at 15:52
  • @JeffScottBrown That's what I was suggesting. Was a cleaner implementation using transients. However, you're right. I wasn't answering the question about he compilation error. – Joshua Moore Aug 21 '19 at 15:56
  • "That's what I was suggesting. Was a cleaner implementation using transients. " - I see. Maybe that is what the asker is looking for. I thought they wanted to know about the compilation error. Could be my mistake. – Jeff Scott Brown Aug 21 '19 at 16:02

1 Answers1

2

One of the error messages you show there includes the following:

[Static type checking] - No such property: fullName for class: Person
 @ line 8, column 8.
       fullName person.fullName
          ^

1 error

That looks like you are referring to person.fullName instead of person.fullName(). person.fullName would work if you had a method in the Person class named getFullName(), but you don't.

See the project at https://github.com/jeffbrown/fullnamequestion.

https://github.com/jeffbrown/fullnamequestion/blob/81cb45f176f887edf90de783a976c48154c3f9bc/server/grails-app/views/person/_person.gson

import fullnamequestion.Person

model {
    Person person
}

json {
    lastName person.lastName
    firstName person.firstName
    fullName person.fullName()
}

That works fine:

~ $ git clone https://github.com/jeffbrown/fullnamequestion.git
Cloning into 'fullnamequestion'...
remote: Enumerating objects: 144, done.
remote: Counting objects: 100% (144/144), done.
remote: Compressing objects: 100% (120/120), done.
remote: Total 144 (delta 5), reused 144 (delta 5), pack-reused 0
Receiving objects: 100% (144/144), 188.53 KiB | 2.62 MiB/s, done.
Resolving deltas: 100% (5/5), done.
~ $ 
~ $ cd fullnamequestion/
~ $ ./gradlew server:bootRun

> Task :server:bootRun

Grails application running at http://localhost:8080 in environment: development
<==========---> 83% EXECUTING [18s]
> :server:bootRun

Send a request to render the view:

~ $ curl http://localhost:8080/person/1
{"lastName":"Lee","firstName":"Geddy","fullName":"Geddy Lee"}
Jeff Scott Brown
  • 26,804
  • 2
  • 30
  • 47
  • This is correct and looking at your sample project helped. One of the problems I found was that if in my domain class if I called my method "def myMethod()" it would give me a NoSuchMethodError but if I call it "String myMethod" it works correctly. I was doing the former originally – user779643 Aug 21 '19 at 17:53
  • That doesn't make sense to me and I can't reproduce it. The return type of the method shouldn't be relevant. – Jeff Scott Brown Aug 21 '19 at 18:03
  • Your comment there combined with some items elsewhere in this questions suggest to me that you may be confused about properties vs methods. `per.fullName` will evaluate to the value of the `fullName` property, which is different that invoking `per.fullName()` which will invoke a method named `fullName`. – Jeff Scott Brown Aug 21 '19 at 18:04
  • https://github.com/kingaaronm/fullnamequestion - I forked your project with the change to domain/Person.groovy to show what I mean – user779643 Aug 21 '19 at 18:40
  • @user779643 Your code appears to work. See http://jeffscreencasts.s3.amazonaws.com/user779643.mp4. – Jeff Scott Brown Aug 21 '19 at 19:11
  • Are you making changes to the domain class while the app is running and dynamically reloading those changes? – Jeff Scott Brown Aug 21 '19 at 19:14
  • 1
    If you are changing the method signature in the domain class while the app is running, that would explain the behavior you are seeing. The issue isn't that you can't call methods on a domain class form a JSON View. The issue is related to class reloading issues. – Jeff Scott Brown Aug 21 '19 at 19:18