Grails 4 service not being injected inside Grails Data Service - grails

This is about a Grails service injected into a Data Service. The problem is that the injected service is null at runtime. Here is an example.
class MessagingService {
def sendEmail(String message) {
...
}
}
interface IFlowService {
...
}
#Service(Flow)
abstract class FlowService implements IFlowService {
MessagingService messagingService
void sendFoo() {
messagingService.sendEmail(message)
}
}
FlowService and MessagingService both reside under grails-app/services.
When FlowService calls sendEmail there is an NPE because messagingService is null.
MessagingService is hand-written and is not associated with a domain.
This project uses Grails 4.0.10 and the issue occurred several times. When the usual Gails magic (i.e. injection) didn't work I solved the first one or two issues with kludges, you know, just to avoid getting stuck.
Now it seems to me the issue is quite predictable, it happens every time I write a service not associated with a domain. Did I miss something in the documentation? What is the appropriate way to handle this?
Kludge: To get around the issue I include a method sayHi in the problematic service. It just logs a debug message. I invoke sayHi from BootStrap to check that it works. It does, surprisingly. Then I add code in BootStrap to assign the service to the supposedly injected property in the service. [Shudder]

I tried to reproduce the same-
interface IFlowService {
}
#Service(Flow)
abstract class FlowService implements IFlowService {
MessagingService messagingService
void hello() {
println "hello"
messagingService.hi() // <- NPE
}
}
class MessagingService {
void hi() {
println "hi"
}
}
This seems to be a bug to be in Grails. But you can easily solve this (probably as a workaround) by just adding #Autowired in the service-
import org.springframework.beans.factory.annotation.Autowired
#Service(Flow)
abstract class FlowService implements IFlowService {
#Autowired
MessagingService messagingService
void hello() {
println "hello"
messagingService.hi() // <- No NPE
}
}
It prints-

Related

Can't inject the guice dependency in the jersey filter

In the process of setup a bridge between guice and jersey, I ran into one problem.
When trying to create a jersey filter, I was unable to inject guice dependencies into it.
I found a duplicate, however there is no solution to the problem there.
Everything is exactly the same.
The only difference is that I don't get a startup error. The filter works, but my dependencies are null.
Interestingly, Filter and HttpFilter work fine. But it doesn't really work for me.
There's another thing that's interesting. In the resource, which I understand is an HK2 dependency, I can inject guice bean.
#ApplicationPath("/test")
private static class TestApplicationConfig extends ResourceConfig
{
public TestApplicationConfig()
{
register(JacksonFeature.class);
register(AuthFilter.class);
register(new ContainerLifecycleListener()
{
public void onStartup(Container container)
{
ServletContainer servletContainer = (ServletContainer) container;
ServiceLocator serviceLocator = container.getApplicationHandler().getServiceLocator();
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
Injector injector = (Injector) servletContainer
.getServletContext()
.getAttribute(Injector.class.getName());
guiceBridge.bridgeGuiceInjector(injector);
}
public void onReload(Container container)
{
}
public void onShutdown(Container container)
{
}
});
}
}
In ServletModule child.
serve(path).with(ServletContainer.class, ImmutableMap.of(
"javax.ws.rs.Application", TestApplicationConfig.class.getName(),
"jersey.config.server.provider.packages", sb.toString()));
I trying with register(AuthFilter.class) and #Provider
#Singleton
#Provider
public class AuthFilter implements ContainerRequestFilter
{
#Inject
private SomeInjectedService someInjectedService; **// null here**
#Context
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException
{
// some code
}
}
SomeInjectedService I register by guice
bind(SomeInjectedService.class).asEagerSingleton();
Where can I start diagnosing and what can I do?
UPD:
I noticed different behavior when using different annotations.
If I use javax.inject.Inject, I get the following error message.
org.glassfish.hk2.api.MultiException: A MultiException has 3 exceptions. They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=SomeInjectedService,parent=AuthFilter,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1496814489)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of some.package.AuthFilter errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on some.package.AuthFilter
If com.google.inject.Inject, just null. As I understand this method is not correct.
Considering that javax Inject is trying to inject the service but can't find it. Can we conclude that the bridge is not working correctly? But if it's not working correctly, why can I inject this service into my resource?
#Path("/test")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class SomeResource
{
private final SomeInjectedService someInjectedResource;
#Inject // here I use javax annotation and this code working correctry
public SomeResource(SomeInjectedService someInjectedResource)
{
this.someInjectedResource = someInjectedResource;
}
#GET
#Path("/{user}")
public Response returnSomeResponse(#PathParam("user") String user) throws Exception
{
// some code
}
}

Injecting service with PostContstruct into a taglib

I have a service with a PostConstruct annotated init method to ensure that it does not run until dependency injection has completed.
#PostConstruct
private void init() {
// Create some datasources on the fly
MyDomain.list().each {
createDataSource(it)
}
}
I now have a need to inject this service into taglib, but the application will not boot with the following error..
java.lang.IllegalStateException: Method on class [com.me.MyDomain] was
used outside of a Grails application
The stacktrace specifically points to the usage above and of course it boots fine when I remove.
Does anyone know of a 'credible' way around this?
try like:
#PostConstruct
void init() {
Domain.withNewSession {
println Domain.count
}
}
or
#PostConstruct
void init() {
Domain.withTransaction {
println Domain.count
}
}

How do we hook into before/After message processing using #RabbitListener

Problem: I am migrating from MessageListener interface impl to #RabbitListener. I had logic like this where I was doing "pre" and "post" message processing on a MessageListener that was inherited by several classes
example:
public AbstractMessageListener implements MessageListener {
#Override
public void onMessage(Message message) {
//do some pre message processing
process(Message message);
// do some post message processing
}
protected abstract void process(Message message);
}
Question: Is there a way I can achieve something similar using #RabbitListener annotation Where I can inherit pre/post message processing logic without having to re-implement or call the pre/post message processing inside each child #RabbitListener annotation and all the while maintaining a customizable method signatures for the child #RabbitListener? Or is this being too greedy?
Example desired result:
public class SomeRabbitListenerClass {
#RabbitListener( id = "listener.mypojo",queues = "${rabbitmq.some.queue}")
public void listen(#Valid MyPojo myPojo) {
//...
}
}
public class SomeOtherRabbitListenerClass {
#RabbitListener(id = "listener.orders",queues ="${rabbitmq.some.other.queue}")
public void listen(Order order, #Header("order_type") String orderType) {
//...
}
}
with both these #RabbitListener(s) utilizing the same inherited pre/post message processing
I see there is a 'containerFactory' argument in the #RabbitListener annotation but i'm already declaring one in the config... and i'm really sure how to achieve the inheritance I desire with a custom containerFactory.
Updated Answer: This is what I ended up doing.
Advice defintion:
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.amqp.core.Message;
/**
* AOP Around advice wrapper. Every time a message comes in we can do
* pre/post processing by using this advice by implementing the before/after methods.
* #author sjacobs
*
*/
public class RabbitListenerAroundAdvice implements MethodInterceptor {
/**
* place the "AroundAdvice" around each new message being processed.
*/
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Message message = (Message) invocation.getArguments()[1];
before(message)
Object result = invocation.proceed();
after(message);
return result;
}
declare beans: In your rabbitmq config declare the advice as a Spring bean and pass it to the rabbitListenerContainerFactory#setAdviceChain(...)
//...
#Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory( cachingConnectionFactory() );
factory.setTaskExecutor(threadPoolTaskExecutor());
factory.setMessageConverter(jackson2JsonMessageConverter());
factory.setAdviceChain(rabbitListenerAroundAdvice());
return factory;
}
#Bean
public RabbitListenerAroundAdvice rabbitListenerAroundAdvice() {
return new RabbitListenerAroundAdvice();
}
// ...
Correction
You can use the advice chain in the SimpleRabbitListenerContainerFactory to apply an around advice to listeners created for #RabbitListener; the two arguments are the Channel and Message.
If you only need to take action before calling the listener, you can add MessagePostProcessor(s) to the container afterReceivePostProcessors.
The inheritance isn't possible here because annotation processing on the POJO methods and MessageListener implementation are fully different stories.
Using MessageListener you fully have control around the target behavior and the container.
With the annotations you deal only with the POJO, framework-free code. The particular MessageListener is created on the background. And that one fully based on the annotated method.
I'd say we can achieve your requirement using Spring AOP Framework.
See the recent question and its answers on the matter: How to write an integration test for #RabbitListener annotation?

Crashes related to GraphRepository#findAll() when using AspectJ

This line in TopLevelTransaction (neo4j-kernel-2.1.2) throws a NullPointerException every time I call next() on an iterator obtained via GraphRepository#findAll():
protected void markAsRollbackOnly()
{
try
{
transactionManager.getTransaction().setRollbackOnly(); // NPE here
}
catch ( Exception e )
{
throw new TransactionFailureException(
"Failed to mark transaction as rollback only.", e );
}
}
I found some threads about similar crashes with slightly different stack traces. The accepted solution on this question is to use "proxy" transaction management, but that seems like a band-aid solution. This question also mentions "proxy" transaction management and suggests that there might be something wrong with the #Transactional annotation when using AspectJ.
Is this legitimately a bug, or have I just set up my project incorrectly? My code is essentially the same as in my standalone hello world, with a slightly more complex main class:
#Component
public class Test2 {
#Autowired
FooRepository repo;
public static void main(String[] args) {
AbstractApplicationContext context = new AnnotationConfigApplicationContext("test2");
Test2 test2 = context.getBean(Test2.class);
test2.doStuff();
}
public void doStuff() {
createFoo();
printFoos();
}
#Transactional
public Foo createFoo() {
Foo foo = new Foo();
foo.setName("Derp" + System.currentTimeMillis());
repo.save(foo);
System.out.println("saved " + foo.toString());
return foo;
}
#Transactional
public void printFoos() {
Iterable<Foo> foos = repo.findAll();
System.out.println("findAll() returned instance of " + foos.getClass().getName());
Iterator<Foo> iter = foos.iterator();
System.out.println("iterator is instance of " + iter.getClass().getName());
if(iter.hasNext()) {
iter.next(); // CRASHES HERE
}
}
}
I can post my POM if needed.
I didn't find a bug. Two or three things are required to make this work, depending on whether you want to use proxy or AspectJ transaction management.
First, transaction management must be enabled. Since I'm using annotation-based configuration, I did this by annotating my #Configuration class with #EnableTransactionManagement. Contrary to the docs, the default mode now seems to be AdviceMode.ASPECTJ, not AdviceMode.PROXY.
Next, you need to ensure that the Iterator is used within a transaction. In my example, if I use AdviceMode.PROXY the entire bean containing the #Autowired repository has to be annotated #Transactional. If I use AdviceMode.ASPECTJ I can annotate just the method. This is because the call to the method using the iterator is a self-call from within the bean, and proxy transaction management cannot intercept and manage internal calls.
Finally, if you're using AdviceMode.ASPECTJ you must set up weaving as discussed here.

Grails unit tests: Accessing defined beans via grailsApplication

I have some (non-Grails-artifact) classes that access the service layer beans via passing around the grailsApplication object. However I'm having trouble unit testing the classes implemented in this way. Why doesn't the bean get registered in the main context?
#TestMixin(GrailsUnitTestMixin)
class ExampleTests {
void setUp() {}
void tearDown() {}
void testSomething() {
defineBeans {
myService(MyService)
}
assert grailsApplication.mainContext.getBean("myService") != null
}
}
The above code fails with:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myService' is defined
What I'm trying to do is access services from plain old Java classes via the grailsApplication. This works, but not in unit test environment. Should I do it differently?
class POJO {
MyService myService;
public POJO(GrailsApplication grailsApplication) {
myService = (MyService) grailsApplication.getMainContext().getBean("myService");
}
}
The answer is that in the GrailsUnitTestMixin the applicationContext that holds your beans is set as the parentContext in the grailsApplication
beans.registerBeans(applicationContext)
static void initGrailsApplication() {
...
//the setApplicationContext in DefaultGrailsApplication set's the parentContext
grailsApplication.applicationContext = applicationContext
}
So you can get your beans with:
defineBeans {
myService(MyService)
}
assert applicationContext.getBean("myService")
assert grailsApplication.parentContext.getBean("myService")
EDIT
Today I faced the same problem, and my solution is:
#Before
void setup() {
Holders.grailsApplication.mainContext.registerMockBean("myService", new MyService())
}
In my case (grails 2.4.4) the accepted solution didn't work but pointed me in the right direction, this line worked instead as the bean factory in the mainContext within my unit test was an OptimizedAutowireCapableBeanFactory
Holders.grailsApplication.mainContext.beanFactory.registerSingleton('myBean', new MyBeanClass())
I have spent some time with the same issue, in my case running grails 2.2.4 and having (in src/groovy):
import grails.util.Holders
class SomeClass {
transient myService = Holders.grailsApplication.mainContext.getBean 'myService'
.....
}
Which is a bit different to question author, but at least it will be useful for someone coming from search engine results
Nevertheless accepted answer did not work for me, so I came up with a bit different approach of mocking and registering service used in SomeClass.
import grails.util.Holders
.. other imports
#TestMixin(GrailsUnitTestMixin)
class SomeClassTests {
#Before
void setUp() {
Holders.grailsApplication = grailsApplication
defineBeans {
myService(MyServiceMock)
}
}
....
}
class MyServiceMock extends MyService {
// overriden methods here
}

Resources