6

I have a custom-made Spring which is bundled in a jar, which is then set as a dependency to my Grails app. I load the app-context for the bean with importBeans statement in resoueces.groovy like

beans = {
  importBeans('classpath:app-context-my-component.xml')
}

The app-context-my-component.xml has some bean definitions and the following lines

<context:annotation-config />
<context:property-placeholder location="classpath:my-component.properties" />

The component I'm trying to use with Grails is annotated with @Component("myComponent").

Grails is loading the external application context. I know it because I first didn't have the .properties file on classpath and there we're no fallback mechanism for missing property in my @Value declarations.

In the Grails controller, the component is used as

class MyController {

  def myComponent

  def someaction() {
    myComponent.doSomething()
  }
}

The result is a NullPointerException i.e. the autowiring of the component didn't work after all. I tried to use @Autowired in the controller, but that gave such a strange problems that I thought it cannot be the road I want to take.

Grails version in use is 2.3.6 The Spring component is also set to use Spring version 3.2.7 to avoid incompatibilities.

UPDATE

Now with again time in my hands for this issue, I set up Spring logging in order to figure out what's happenig. Well, there's plenty of log that Spring context loading produces, but here's what I managed to grep from the whole lot

INFO xml.XmlBeanDefinitionReader Loading XML bean definitions from class path resource [app-context-my-component.xml]
INFO support.PropertySourcesPlaceholderConfigurer Loading properties file from class path resource [my-component.properties]
DEBUG framework.CglibAopProxy Unable to apply any optimisations to advised method: public myapp.external.MyComponent myapp.MyService.getMyComponentClient()
DEBUG framework.CglibAopProxy Unable to apply any optimisations to advised method: public myapp.external.MyComponent myapp.MyService.getMyComponentClient()
DEBUG framework.CglibAopProxy Unable to apply any optimisations to advised method: public myapp.external.MyComponent myapp.MyService.getMyComponentClient()
DEBUG framework.CglibAopProxy Unable to apply any optimisations to advised method: public void myapp.MyService.setMyComponentClient(myapp.external.MyComponent)
DEBUG framework.CglibAopProxy Unable to apply any optimisations to advised method: public void myapp.MyService.setMyComponentClient(myapp.external.MyComponent)
DEBUG framework.CglibAopProxy Unable to apply any optimisations to advised method: public void myapp.MyService.setMyComponentClient(myapp.external.MyComponent)

I changed the namespaces of the log, but myapp.external namespace refers to the external jar package, and myapp namespace refers to Grails application namespace. I have changed the usage, so that the external component is used from a Service instead of directly from Controller, but that detail had no change in the behaviour.

Per my understanding, the Spring context loading went well.

UPDATE 2

Based on @th3morg's answer I got an idea to try with XML-based config only, skipping all @Component and such annotations from the bean. And it worked! Now Grails manages to import the beans an no longer causes NPE on use.

Although this solves my problem, at least partially. I'm still interested in solution where Spring annotations could be used.

kaskelotti
  • 4,709
  • 9
  • 45
  • 72
  • Haven't really dug around enough in this area of Grails to give a certain answer. But, try telling Grails which package(s) to scan for beans by adding `grails.spring.bean.packages = [ "com.sample.app..." ]` to `Config.groovy` (the package where `myComponent` is defined or a parent package, Grails will scan sub-packages) – Andrew Oct 15 '14 at 05:36
  • @Andrew thanks for the suggestion, but that didn't have any effect. – kaskelotti Oct 15 '14 at 06:04
  • Hmm, sorry for the bad lead. If possible (and it's a long shot given what you mentioned about a bundled jar...) you might also try moving your Spring XML to a file named `resources.xml` under `grails-app/conf/spring/` – Andrew Oct 15 '14 at 20:07
  • @JAndy Can you elaborate on how you wish to use annotations? Are you saying that you Grails to be able to component scan in order to wire up your beans that are defined in your XML project? Checkout out the section titled "Using Spring Namespaces" here http://grails.org/doc/latest/guide/spring.html#theBeanBuilderDSLExplained – th3morg Oct 23 '14 at 13:30
  • Well, I was missing the whole component-scan from my Spring config. Adding it to resources.groovy helps, but it's simpler to have it on the Spring module as then in Grails one only needs to use importBeans(). – kaskelotti Oct 24 '14 at 03:17
  • @th3morg, please post your comment as an answer or modify the existing. You surely have earned the bounty. – kaskelotti Oct 24 '14 at 03:19
  • All set, thanks @JAndy. Glad you got things working! – th3morg Oct 24 '14 at 04:02

1 Answers1

6

You should make sure that component scanning is setup in your jar. Checkout out the section titled "Using Spring Namespaces" here http://grails.org/doc/latest/guide/spring.html#theBeanBuilderDSLExplained. You can also use a resources.xml and add component scanning to that file if you can't modify your jar.

Alternatively, you can also wire up the beans one by one, though this is cumbersome and tedious:

beans = {
  myComponent(com.my.MyComponent){
    someOtherService = ref('someOtherService') //if there are other beans to wire by name
    propertyOne = "x"
    propertyTwo = 2
  }
}
th3morg
  • 4,321
  • 1
  • 32
  • 45
  • Thanks for the idea on using a debugger. I'll see if I can find the proper tools for this. – kaskelotti Oct 22 '14 at 03:00
  • Use a free trial of IntelliJ IDEA ultimate which is good for 30 days. Great Grails support. Alternatively the STS is pretty decent and free. – th3morg Oct 22 '14 at 03:02