I want to use g.formatNumber in service, I have tried a below method, Which i got online. This is not working, its giving me the error "Cannot invoke method formatNumber() on null object", The code is below
import org.springframework.beans.factory.InitializingBean
class MyService implements InitializingBean {
boolean transactional = false
def gspTagLibraryLookup // being automatically injected by spring
def g
public void afterPropertiesSet() {
g = gspTagLibraryLookup.lookupNamespaceDispatcher("g")
assert g
}
def getFormattedNumber(){
def number = g.formatNumber(number: 5000,234 , type: "number" , maxFractionDigits: 2)
return number
}
}
How to do this.
I want to use g.formatNumber in service
Rather than jumping through the hoops you need to use a taglib within a service, it would be simpler to just use java.text.NumberFormat directly
NumberFormat format = NumberFormat.getNumberInstance()
format.maximumFractionDigits = 2
def number = format.format(5000.234)
If the service method is being called from a web request handling thread then you may wish to use the LocaleContextHolder to get the correct locale for the current web request, rather than just using the server's default.
This should work
def g = grailsApplication.mainContext.getBean('org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib');
You will of course need grailsApplication injected by defining it ala
def grailsApplication
Related
I have a class based Dependency that connects to the database, and returns a session, engine, and database, so I can include those dependencies in all routes in my app. Everything works, except that I can't access the properties of the class inside the route. I can access them when I specifically set the Dependency at the route level, but since I want this injected into every route, I would like to include it at the router level. How do I do this?
Some code, to illustrate:
Dependency:
class DatabaseSession:
engine = None
session = None
db = None
def __init__(self, x_code: str = Header(None)):
if x_code:
self.engine, self.session, self.db = get_database_objects(x_code)
else:
raise HTTPException(status_code=400, detail="No code submitted")
Main app
app = FastAPI()
app.include_router(users.router, dependencies=[Depends(DatabaseSession)])
Example route, and what I'd like to accomplish
#router.get("/users/", tags=["users"], response_model=List[UserBase])
async def retrieve_all_users():
async with db as database:
# get all the users
users = session.query(User).all()
return users
The problem is, db, nor session, are defined now in the route, since I'm injecting the dependency at the router level. If I do it as shown below, it works fine:
#router.get("/users/", tags=["users"], response_model=List[UserBase])
async def retrieve_all_users(db_settings: DatabaseSession = Depends(DatabaseSession)):
async with db_settings.db as database:
# get all the users
users = db_settings.session.query(User).all()
return users
How do I get access to db and session inside each route while injecting the dependency at the router level? Thanks!
I've had a similar question in the past. See
FastAPI get user ID from API key
Basically, save the dependency response/values in the request object and access it from within the endpoint(s).
Here the documentation:
https://www.starlette.io/requests/
Here the sample code from the answer given to me in the question above.
async def oauth2_scheme(request: Request):
request.state.user_id = "foo"
my_router = APIRouter()
#my_router .get("/")
async def hello(request: Request):
print(request.state.user_id)
app.include_router(
my_router,
dependencies=[Depends(oauth2_scheme)]
)
You can achieve that with a Class-based dependency too. The request object can be accesses in the __call__ method.
from fastapi import FastAPI, Request, Depends
class Simple_dep:
def __call__(self, request: Request):
request.state.test = 'test'
app = FastAPI(
dependencies=[Depends(Simple_dep())]
)
#app.get("/test")
async def root(request: Request):
return {"test": request.state.test}
Just make sure you are using Depends(Simple_dep()) instead of Depends(Simple_dep)
I'm developing a web application where my business logic requires several types of error messages.
Due to this in my services layer I have several calls to the messageSource.
def messageSource
At the same time, my application must support several languages so I need to define the Locale as specified by the user.
To do this, I'm getting the Locale as follows:
def request = RequestContextHolder.currentRequestAttributes().request
Locale myLocale = RequestContextUtils.getLocale(request)
But I note that this code is repeated throughout my service layer. ie:
def myMethod(){
...
messageSource.getMessage("message.code", [args] as Object[],"Default message",getLocale())
...
}
Locale getLocale(){
def request = RequestContextHolder.currentRequestAttributes().request
return RequestContextUtils.getLocale(request)
}
Is there any elegant way to share this method among all my services and controllers? Or is there any other way to improve this behavior?
Grails 2.5.5 - Groovy 2.4.4
Thanks!
You can implement the methods in a Groovy trait, and then use the trait in your services.
src/groovy/com/foo/bar/SessionLocale
trait SessionLocale {
def getMessage(String code, String defaultMessage, Object [] args) {
messageSource.getMessage(code, args, defaultMessage,getLocale())
}
Locale getLocale(){
def request = RequestContextHolder.currentRequestAttributes().request
return RequestContextUtils.getLocale(request)
}
}
grails-app/services/com/foo/bar/SomeService
class SomeService implements SessionLocale {
def myMethod(){
...
getMessage("message.code", "Default message", [args] as Object[])
...
}
}
I'm carrying the locale of my Grails application in the URL, such as
http://myapp.com/LANG/controller/action/id.
Therefore, I adjusted the URLMappings.groovy with the language attribute. Since I would like to save work and don't apply the lang parameter at every link, I have overridden the g:link taglib with the language from params.lang. This works pretty good.
When I do a redirect from a controller, such as
redirect(action: "logout")
I'd like to append the params.lang automatically instead of writing every time
redirect(action: "logout", params: [lang: params.lang])
I found the thread grails override redirect controller method, but I'm unsure how to proceed. Where does this code take part?
How can I override the redirect() method and add the params.lang-attribute?
Please advice, thank you very much.
The easiest way to do this in your application would be to use a bit of meta programming and the BootStrap.groovy for your Grails application. The following is just a simple example of what that might look like:
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
class BootStrap {
def init = { servletContext ->
def ctx = servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
def app = ctx.getBean("grailsApplication")
app.controllerClasses.each() { controllerClass ->
def oldRedirect = controllerClass.metaClass.pickMethod("redirect", [Map] as Class[])
controllerClass.metaClass.redirect = { Map args ->
// new pre-redirect logic
if (!args['params']) args['params'] = [:] // just in case redirect was called without any parameters
args['params']['whatever'] = 'something' // add something into the parameters map
oldRedirect.invoke delegate, args
// new post-redirect logic
}
}
}
def destroy = {
}
}
The above example just wraps the implementation for redirect on all controllers within your Grails application and injects a new parameter called whatever with the value of something.
The above was tested (quickly) using Grails 2.4.2.
Hi there i am still very new to grails and I have not been able to figure out why this is happening.
I have a domain class:
package scheduler
class Client {
String name
static constraints = {}
}
And a controller:
package scheduler
class AdminController {
def create() {
def client = new Client(name:"John")
println client
}
}
Currently I am always getting null for client. Originally the above was a little more complex on the domain class side but I systematically dumbed it down to see if it was a problem there. I still can not get the above working.
The output is always
scheduler.Client : null
Please let me know if I need to provide anymore information.
It's not null, that's just the default output of the toString method that Grails adds. It prints the class name and the id. Since you haven't saved the instance, the id is null. If the instance was null the output would have been null, not scheduler.Client : null
If you want to see the data in the instance, use the Groovy dump() method, e.g.
def client = new Client(name:"John")
println client.dump()
You could also add a toString method that includes the name attribute, e.g.
package scheduler
class Client {
String name
String toString() { name }
}
I'm creating a grails service that will interact with a 3rd party REST API via a Java library. The Java library requires credentials for the REST API by means of a url, username and password.
I'd like to store these credentials in configuration/Config.groovy, make them available to a service and ensure that credentials are available to the service before it requires them.
I appreciate that grailsApplication.config is available to controllers and that through a method of a service the relevant config values can be provided to the service, such as this:
package example
class ExampleController {
def exampleService
def index = { }
def process = {
exampleService.setCredentials(grailsApplication.config.apiCredentials)
exampleService.relevantMethod()
}
}
package example
import com.example.ExampleApiClient;
class ExampleService {
def credentials
def setCredentials(credentials) {
this.credentials = credentials
}
def relevantMethod() {
def client = new ExampleApiClient(
credentials.baseUrl,
credentials.username,
credentials.password
)
return client.action();
}
}
I feel this approach is slightly flawed as it depends on a controller calling setCredentials(). Having the credentials made available to the service automagically would be more robust.
Is either of these two options viable (I currently not familiar enough with grails):
Inject grailsApplication.config.apiCredentials into the service in the controller when the service is created?
Provide some form of contructor on the service that allows the credentials to be passed in to the service at instantiation time?
Having the credentials injected into the service is ideal. How could this be done?
The grailsApplication object is available within services, allowing this:
package example
import com.example.ExampleApiClient;
class ExampleService {
def grailsApplication
def relevantMethod() {
def client = new ExampleApiClient(
grailsApplication.config.apiCredentials.baseUrl
grailsApplication.config.apiCredentials.username,
grailsApplication.config.apiCredentials.password
)
return client.action();
}
}
Even though grailsApplication can be injected in services, I think services should not have to deal with configuration because it's harder to test and breaks the Single Responsibility principle. Spring, on the other side, can handle configuration and instantiation in a more robust way. Grails have a dedicated section in its docs.
To make your example work using Spring, you should register your service as a bean in resources.groovy
// Resources.groovy
import com.example.ExampleApiClient
beans {
// Defines your bean, with constructor params
exampleApiClient ExampleApiClient, 'baseUrl', 'username', 'password'
}
Then you will be able to inject the dependency into your service
class ExampleService {
def exampleApiClient
def relevantMethod(){
exampleApiClient.action()
}
}
In addition, in your Config.groovyfile, you can override any bean property using the Grails convention over configuration syntax: beans.<beanName>.<property>:
// Config.groovy
...
beans.exampleApiClient.baseUrl = 'http://example.org'
Both Config.groovy and resources.groovy supports different environment configuration.
For contexts where you can't inject the grailsApplication bean (service is not one of those, as described by Jon Cram), for example a helper class located in src/groovy, you can access it using the Holders class:
def MyController {
def myAction() {
render grailsApplication == grails.util.Holders.grailsApplication
}
}
The best options are (as from grails docs):
1 - Using Spring #Value annotation
import org.springframework.beans.factory.annotation.Value
class WidgetService {
int area
#Value('${widget.width}')
int width
def someServiceMethod() {
// this method may use the width property...
}
}
2 - Having your class implement GrailsConfigurationAware
import grails.config.Config
import grails.core.support.GrailsConfigurationAware
class WidgetService implements GrailsConfigurationAware {
int area
def someServiceMethod() {
// this method may use the area property...
}
#Override
void setConfiguration(Config co) {
int width = co.getProperty('widget.width', Integer, 10)
int height = co.getProperty('widget.height', Integer, 10)
area = width * height
}
}