Null Pointer exception when calling service method from controller - grails

I have a method in service class which has to be called from the controller. Both the controller and the service class codes are as below.
folder grails-app/services, file FileFactoryService.groovy
package edu.rev.document
import grails.transaction.Transactional
Class FileFactoryService{
Document document = new Document() // Domain object
def build(byte[] fileArray){
String str = new String(fileArray, "UTF-8") // UTF encoding as invoice may contain negative values
String[] lines = str.split("\\r?\\n")
document.version = lines[0].substring(0,1)
document.name = lines[1].substring(0,25)
}
return document.properties.collect()
}
Controller Code: folder: grails-app/controllers, file: FileController.groovy
package edu.rev.document
Class FileController{
def fileFactoryService
def save(){
def file = request.getFile('file')
if(file.empty) {
flash.message = "File cannot be empty"
} else {
def myList = fileService.build(file.getBytes())
}
}
The error thrown is
NullPointer exception when processing [POST]/../save
Cannot invoke method build() on NULL object
Can you please point me to the mistake I might be committing? Let me know if you need any other information
EDIT:This is the code. Just a heads up, the same logic when taken out of the service and implemented in the controller itself works perfectly alright. One more thing, when I use the "." operator inside the service (say document.), it doesnt show may any auto complete options like document.name.

Posting all of your code helps in finding the error. This line in your controller class
def myList = fileService.build(file.getBytes())
should be
def myList = fileFactoryService.build(file.getBytes())

In your controller class, you declared the service as :
def fileService
But the name of your service class is :
Class FileFactoryService
For Grails dependency injection to work, you need to name the variable like your class name :
def fileFactoryService
Then this should work.

Related

How to dynamically add all methods of a class into another class

I have a global shared library on Jenkins implicitly loaded on all pipelines, then my Jenkinsfile is like that:
new com.company.Pipeline()()
And then the shared library has on directory src/com/company some files, below the Pipeline.groovy class:
package com.company
import static Utils.*
def call() {
// some stuff here...
}
The problem is, this way I have to static declare all methods, thus I lose the context and cannot access jenkins' methods easly without the Pipeline class' instance. As you can see here they passing this to the method mvn.
Thinking of avoid this I was wondering about dynamically add all methods as closures by calling Utils.install this instead of using import static Utils.*, then my Utils.groovy is something like that:
package com.company
private Utils() {}
static def install(def instance) {
def utils = new Utils()
// Some extra check needed here I know, but it is not the problem now
for (def method in (utils.metaClass.methods*.name as Set) - (instance.metaClass.methods*.name as Set)) {
def closure = utils.&"$method"
closure.delegate = instance
instance.metaClass."$method" = closure
}
}
def someMethod() {
// here I want to use sh(), tool(), and other stuff freely.
}
But it raises an GStringImpl cannot be cast to String error, I believe .& do not work with variables, how can I convert a method into closure having the method name on a variable? I have the MetaMethod mostly being a CachedMethod instance, if it were possible to turn it a ClosureMetaMethod instance maybe the problem can be solved, but whenever I search for method to closure conversion for groovy I just found the .& solution!
If I use instance.metaClass.someMethod = utils.&someMethod it do work, but I want it to be dinamic as I add new methods without needing to worry about sharing it.
There is a way to do it dynamically. Notation utils.&someMethod returns a MethodClosure object that can be simply instantiated with its constructor:
MethodClosure(Object owner, String method)
Consider following example:
class Utils {
def foo() {
println "Hello, Foo!"
}
def bar() {
println "Hello, Bar!"
}
}
class Consumer {
}
def instance = new Consumer()
def utils = new Utils()
(utils.metaClass.methods*.name - instance.metaClass.methods*.name).each { method ->
def closure = new MethodClosure(utils, method)
closure.delegate = instance
instance.metaClass."$method" = closure
}
instance.foo() // Prints "Hello, Foo!"
instance.bar() // Prints "Hello, Bar!"
In this example I use def closure = new MethodClosure(utils, method) to get object method reference and then add this method to instance object. I hope it helps.

GroovyCastException metaclass i18n

This question is connected with another.
I'd like to add properties to constructor and overwrite getLocalisedMessage() function to get proper translated message with error. First I want to overload constructor to set properties, but when I add:
GroovyCastException.metaClass.constructor = { Object objectToCast, Class classToCastTo ->
def constructor = GroovyCastException.class.getConstructor(Object, Class)
def instance = constructor.newInstance(objectToCast, classToCastTo)
// ... do some further stuff with the instance ...
println "Created ${instance} and executed!"
instance
}
and then get thrown GroovyCastException I don't get println in console.
Why?
How to overload constructor, set properties (objectToCast, classToCastTo) and then overload getLocalizedMessage?
I tried also:
def originalMapConstructor = GroovyCastException.metaClass.retrieveConstructor(Map)
GroovyCastException.metaClass.constructor = { Map m ->
// do work before creation
print "boot do work before creation "
m.each{
print it
}
print "boot do work before creation 2"
def instance = originalMapConstructor.newInstance(m)
// do work after creation
print "boot do work after creation"
instance
}
I 've put it in controller (right before catching exception) and in Bootstrap.groovy. Unfortunatelly there is no printlns in console output.
You're better off not using meta-programming to do internationalization. In grails, you should do it in the view layer with the <g:message> tag if possible. If not, the next best choice is the controller layer.
If you just want to display localized messages on an error page when an exception occurs, the best practice is to have a "500" URL mapping, and render the exception with a <g:renderException> in the view.
If you want to intercept the exception, you can change the "500" URL mapping to a controller and wrap it there before passing it to the view. Example:
// UrlMappings.groovy
class UrlMappings {
static mappings = {
...
"500"(controller:"error", method: "serverError")
}
}
// ErrorController.groovy
class ErrorController {
def serverError() {
def exception = request.exception.cause
if (exception instanceof GroovyCastException) {
exception = new LocalizedGroovyCastException(exception)
}
[exception: exception]
}
}
And then do your localization in a new class LocalizedGroovyCastException.

Pass value from grails controller to a class inside src/groovy

I have a Grails application. I want to use a value from Grails controller class (say MyController) inside a class in src/groovy/MyClass.groovy
How can I pass the value from Grails controller class to this class? I couldn't find anything relevant.
I tried this:
class MyController {
def name = "myapp"
}
Class MyClass{
def username = MyController.name
}
Please correct me . Thanks
It is hard to say for sure without knowing what you are doing but your probably want to pass the value as an argument to a method in MyClass and you probably don't want the value to be a field in the controller class.
class MyController {
def someControllerAction() {
def name = // I don't know where you are
// getting this value, but you got it from somewhere
def mc = new MyClass()
mc.someMethod(name)
// ...
}
}
class MyClass {
def someMethod(String name) {
// do whatever you want to do with the name
}
}
Or you could pass the value as a constructor argument:
class MyController {
def someControllerAction() {
def name = // I don't know where you are
// getting this value, but you got it from somewhere
def mc = new MyClass(name: name)
// ...
}
}
class MyClass {
def name
}
I hope that helps.

Grails: why would this service class be null?

Given this grossly simplified rendition of the setup:
package net.myexample.plugin
class MyExampleService {
Map doMunge(Map m) {
// do stuff to 'm'
return m
}
}
/****************************** BREAK: NEXT FILE ******************************/
package net.myexample.plugin
class MyTagLib {
static namespace = 'p'
def myExampleService
def tag = { attrs, body ->
def m = doMungeAndFilter(attrs.remove('m'))
out << g.render(template: '/template', plugin: 'my-example-plugin', model: m)
}
Map doMungeAndFilter(def m) {
def mm = myExampleService.doMunge(m)
// do stuff to 'm'
return mm
}
}
/****************************** BREAK: NEXT FILE ******************************/
package net.myexample.app
import net.myexample.plugin.MyExampleService
class MyExampleService extends net.myexample.plugin.MyExampleService {
def doMunge(def m) {
def mm = super.doMunge(m)
// do more stuff to 'mm'
return mm
}
}
/****************************** BREAK: NEXT FILE ******************************/
package net.myexample.app
import net.myexample.plugin.MyTagLib
class MyTagLib extends net.myexample.plugin.MyTagLib {
static namespace = 'a'
def myExampleService
def tag = { attrs, body ->
def m = doMungeAndFilter(attrs.remove('m'))
out << g.render(template: '/template', plugin: 'my-example-plugin', model: m)
}
Map doMungeAndFilter(def m) {
def mm = super.doMungeAndFilter(m)
// do more stuff to 'mm'
return mm
}
}
/**
* But we get an exception that cites that it cannot call 'doMunge' on a null
* object -- which could only be 'myExampleService'
*/
Why would the service appear to be null when the method on the app's taglib calls its superclass (the taglib on the plugin), which in turn calls the method on the service?
The best theory I could come up with is that the service is not actually being instantiated in the app's taglib class because there are no explicit references to it aside from the def. I presume that this is the case because if I move all the logic from service class's method into the taglib's method, it works as expected.
(For the sake of painting a complete picture: MyExampleService.doMunge is called in other places, whereas the subsequent filtering (in MyTagLib.doMungeAndFilter) is only needed for the taglib.)
Alternatively: if I move doMungeAndFilter into another service class, creating the base version in the plugin and extending it in the app, that works fine. Which I suppose is an acceptable conclusion, though it feels like bloat to create another service class just to support the taglib like that.
Thoughts? Tips? Glaring errors or omissions?
Remove the def myExampleService from the subclass taglib. A property like that in Groovy compiles to a private field plus a public getter and setter, so in the superclass taglib you have implicitly
private Object myExampleService;
public void setMyExampleService(Object svc) {
this.myExampleService = svc;
}
// getter similar
When you declare myExampleService again in the subclass the subclass gets its own private field (with the same name) and the setter gets overridden to store the supplied value in this subclass field instead of the superclass one. Spring calls the setter to inject the service, so the end result is that the superclass private myExampleService never gets set, hence the null pointer exception when trying to call myExampleService.doMunge in the superclass.
The subclass has access to the superclass property via the inherited getter and setter so it doesn't need to re-declare it.
This is just a quick guess, but is you taglib class file located under /grails-app/taglib, or somewhere in your /src directory? I've noticed I can't get services to inject (automatically, at least) into classes located outside the /grails-app folder.

how to call service from controller in grails

I have a service class and i am trying to call the method of the service in my controller as below.
class LogListController {
def ListLogDetails = {
println "We are inside List log Details-->"+params
def logListHelperService
logListHelperService.getFilePath(params)
}}
Exception Message: Cannot invoke method getFilePath() on null object
what is my mistake there..
def logListHelperService
must be declared outside of the ListLogDetails definition
def logListHelperService
def ListLogDetails = {
println "We are inside List log Details-->"+params
logListHelperService.getFilePath(params)
}
should work

Resources