Injecting grails-app classes in Grails - grails

Please note: Although my specific question at hand involves the Grails Shiro plugin, I believe this to be a core Grails question at heart. And so any battle weary Grails veteran should be able to answer this, regardless of their experience with Grails Shiro.
Using the Grails Shiro plugin (via grails shiro-quick-start) produces a Shiro realm class under grails-app/realms. For instance, running:
grails shiro-quick-start --prefix=com.example.me.myapp.Mongo
...will produce:
myapp/
grails-app/
realms/
com/
me/
myapp/
MongoDbRealm.groovy
Where MongoDbRealm is the Shiro realm.
package com.example.me.myapp
class MongoDbRealm {
FizzClient fizzClient // How to inject?
BuzzClient buzzClient // How to inject?
FooFactory fooFactory // How to inject?
// lots of auth-centric, generated code here...
}
Let's pretend that MongoDbRealm is very complicated and needs to be injected with lots of complicated objects such as service clients and factories, etc. How do I properly inject MongoDbRealm?
Will #PostConstruct work here? Can I inject Grails services into it like I do with controllers? Something else?
Again, I would imagine that dependency injection works the same here (with Grails Shiro and my MongoDbRealm) as in any other class defined under grails-app. I just don't understand how grails-app/* dependency injection works.

Plugins that support defining classes under grails-app typically do so by defining a new type of artifact, and specify an ArtefactHandler implementation to manage that. The Grails ArtefactHandlerAdapter class implements that interface and provides a lot of common functionality, so that's often used, and is used in the plugin's RealmArtefactHandler class.
Dependency injection would be configured in the newInstance method. You can see where I did this for one of my plugins here. Since the Shiro plugin doesn't override that method from the base class, it looks like dependency injection isn't supported.
Note that using #PostConstruct (or implementing InitializingBean) would work if the realm classes were registered as Spring beans, but it doesn't look like that's the case in this plugin.
I try to avoid using the Holders class since in most cases it's straightforward to use DI instead of pulling in dependencies explicitly, but it looks like you will need to use that approach here, e.g. fizzClient = Holders.applicationContext.fizzClient (assuming that is registered as the "fizzClient" bean).

Related

How do you create factories for classes with dependencies

If I have a class that requires a dependency through its constructor:
public MyClass( IDependencyInterface dependency )
and the dependency uses a factory/builder (it is still confusing to me the distinction between the two) to set its parameters:
IDependencyInterface dependency = dependencyFactory
.ChangeSomeParameter(someValue)
.ChangeSomeOtherParameter(someOtherValue)
.Build();
How do I create the factory for MyClass without passing in other factories to instantiate the required dependancies?
public MyClassFactory
{
private SomeParam _someParam;
private IDependencyFactory _dependencyFactory;
public myClassFactory( IDependencyFactory dependencyFactory)
{
_dependencyFactory = dependencyFactory;
}
public ImyClassFactory ChangeSomeParameter(someParam)
{
_someParam = someParam;
}
public IMyClass Build()
{
Dependency dependency = _dependencyFactory
.ChangeSomeParameter( _SomeParam )
.Build();
return MyClass(dependency);
}
}
How do I prevent from having to pass the factories of the dependencies required for me to build “MyClass” when I create my MyClassFactory? Or is it correct, that you need to pass in the factories of every dependency into the factory for the class with dependencies?
P.S. I plan on making the factories singletons that are instantiated at run time and passed around. Also I am new to Dependency Injection. Please let me know if there is a better way to use factories with interfaces.
If you are new to dependency injection, I would say: you don't.
Resolving dependencies and creating the vast majority of factories is a purpose of the dependency injection service provider. You get this feature by using a dependency injection component somebody else wrote, e.g. Microsoft.Extensions.DependencyInjection.
In general, application code merely lists its dependencies, for example by merely declaring them as constructor arguments. Services don't care how they or their dependencies are created. One role of dependency injection is inversion of control which popularly said means don't call us, we'll call you. This should especially hold for constructors when talking about dependency injection.
As soon as you start breaking your head over how to create or pass around factories, you're violating several principles of good design.
Have a look at the Dependency injection in ASP.NET Core article on learn.microsoft.com. It has more useful links at the bottom of the page. It is written with writing ASP.NET Core web sites/applications in mind, but most of the article in fact deals with the principles of modern software development (such as inversion of control) that apply in general for any application.

DefaultMessageCodesResolver in Grails

When validating domainclasses in Grails, it uses the DefaultMessageCodesResolver from Spring to "extend" the set of i18n-keys to try and lookup. I would like to simplify this, and have therefore implemented my own SimpleMessageCodesResolver by extending the MessageCodesResolver interface.
However, I can't seem to make Grails pick up on this. I've declared it as a custom dependency injection, trying to override, what Spring normally does:
messageCodesResolver(SimpleMessageCodesResolver)
I still see the DefaultMessageCodesResolver when looking at the domain object... Any ideas how to make this work?
I belive your custom dependency injection should be:
defaultMessageCodesResolver(SimpleMessageCodesResolver)
MessageCodesResolver is an interface, but not spring bean as DefaultMessageCodesResolver instance is.

Change AccessDecisionManager to UnanimousBased in Grails Spring Security Plugin

We're using the Grails spring security plugin:
http://grails.org/plugin/spring-security-core
I simply want to change the default access decision manager from the default AffirmativeBased to UnanimousBased. I do not see it documented anywhere in the plugin manual:
http://grails-plugins.github.io/grails-spring-security-core/docs/manual/
Does anyone know if it's possible to change this?
I added one additional voter, "myVoter" which is detected and working fine.
grails.plugins.springsecurity.voterNames = [
'myVoter', 'authenticatedVoter', 'roleVoter',
]
Based on Burt Beckwith's "Hacking the Grails Spring Security Plugin" [http://www.slideshare.net/gr8conf/hacking-the-grails-spring-security-plugins], it should be possible to simply provide a different implementation of the accessDecisionManager bean. Something like this:
accessDecisionManager(org.springframework.security.access.vote.UnanimousBased)
in resources.groovy
When I tried this, I had trouble with the constructor syntax in the bean definition. The access decision manager wants a list of voters in the constructor and I couldn't quote figure out how to get my voters defined in config.groovy as parameters to the constructor. I was about to derive my own decision manager (with parameterless constructor) from UnanimousBased when I stumbled upon the source code for AuthenticatedVetoableDecisionManager in the Grails Spring Security Plugin. This class splits the voters in half... anything deriving from AuthenticatedVoter will immediately fail if any are denied (e.g. AUTHENTICATED_FULLY family), but all other voters will pass if any are granted (e.g. RoleVoter). I wanted the AuthenticatedVoter functionality for my custom voter so I simply derived from AuthenticatedVoter (making sure to override all of the interface methods so I didn't accidentally get any base class functionality) and stuck with the default decision manager.

Using resources.groovy to define services

I'm using the resources.groovy to declare a service e.g.
aService(com.foo.OrganizationService)
so that I can tie aService to my controllers instead of using organizationService which could change in the future.
I've noticed that the OrganizationService doesn't get treated special like other services "not" declared in the resources.groovy. For example it doesn't get injected with grailsApplication, and likely a hibernateSession etc and other things I've not hit yet....
Now, I know I can manually wire in stuff to my service but I'd rather not have to maintain that...
Is there a special way to declare a service in the resources.groovy so that gets treated like another service that grails loads up?
TIA
The short answer to your question is "no".
Under the covers, Grails services are driven by some intelligent code that is referencing a specific location and expecting certain properties.
Viewing the source code (especially around the ServicesGrailsPlugin.groovy) is a good way to see the "magic" in how these are wired together.
Is there a reason you wouldn't want to use a bonafide Grails service to solve your problem? If you are expecting things like a grailsApplication, it seems like that use is pretty specific to Grails and would be a good candidate for porting over to a "true" Grails service.
Good luck!
So I've come full circle on this. This is a timing problem. Where services haven't been grails initialized yet.
Basically when you use the resources.groovy to do service wiring you run the risk of using a Service that might initialize itself e.g. afterPropertiesSet method or static initializers that use grails services (log, hibernate session, ..) that haven't been injected yet.
So... What I've turned to instead is to create my own BeanBuilder in a BootStrap.groovy file.
BeanBuilder builder = new BeanBuilder(grailsApplication.parentContext)
def bb = builder.beans {
LoginListener(com.foo.LoginListener) {
springSecurityService = ref("springSecurityService")
userService = ref("userService")
}
}
bb.registerBeans(grailsApplication.mainContext)

Where to keep guice injectors?

What is your advice?
I found most suitable for me solution - keep injectors and modules in enumeration classes.
Advantages:
injectors and modules created once,
injectors can be used from different classes while running application (not only at bootstrap),
injectors kept in one place and can be easily found.
Example:
import static ru.package.Modules.*;
public enum Injectors {
FOO_INJECTOR(BarModule.module()),
FOO2_INJECTOR(FOO_INJECTOR.injector(),
Bar2Module.module(), FooModule.module());
private final Injector m_injector;
Injectors (Module... modules) {
m_injector = Guice.createInjector(modules);
}
Injectors (Injector parentInjector, Module... modules) {
m_injector = parentInjector.createChildInjector(modules);
}
public Injector injector() {
return m_injector;
}
}
You appear to be fundamentally misunderstanding how dependency injection works. If you are trying to use a reference to Injector anywhere in your code besides the place where you bootstrap the application, you're not using dependency injection, you're using it as a Service Locator instead. You're forced to prepare an Injector whenever you need to test a class and your classes do not make it clear in their constructors exactly what their dependencies are (since who knows what they'll get out of the Injector in some method if they have or can get a reference to it). Actually, using enum as you've described here is even worse than that: you cannot change the configuration at all, even for testing, because your modules are hardcoded into the enum.
With dependency injection, classes declare their dependencies only and allow the Injector, working transparently (after the initial call to get the root application object), to provide all those dependencies. This makes understanding, testing and changing functionality in your code relatively easy. Anyway, I'd suggest learning more about how DI and Guice are intended to be used... you really should not want to do this.
The bigger question is why?
There should be no need to keep the Injector around, because once the injection is done the Injector should be done and should disappear.
If, however, you really need the Injector, couldn't you simply:
#Inject
private Injector injector;
Is this application web based or is it standalone?

Resources