Native CXF integration in grails - java

Does somebody know how to integrate the cxf framework without using the cxf plugin? I have already published a simple service, but my problem is to inject existing grails service bean in the cxf jaxws bean.
In applicationContext.xml i'm using following definition
<jaxws:server id="jaxwsService" serviceClass="at.pdts.cxf.HelloWorld" address="/hello">
<jaxws:serviceBean>
<bean class="at.pdts.cxf.HelloWorldImpl">
<property name="halloService"><ref bean="helloWorld"></ref></property>
</bean>
</jaxws:serviceBean>
</jaxws:server>
The helloWorld bean is a normal grails serivce class. During startup i get following exception.
Cannot resolve reference to bean 'helloWorld' while setting bean
property 'halloService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'helloWorld' is defined
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<bean id="grailsApplication" class="org.codehaus.groovy.grails.commons.GrailsApplicationFactoryBean">
<description>Grails application factory bean</description>
<property name="grailsDescriptor" value="/WEB-INF/grails.xml" />
<property name="grailsResourceLoader" ref="grailsResourceLoader" />
</bean>
<bean id="pluginManager" class="org.codehaus.groovy.grails.plugins.GrailsPluginManagerFactoryBean">
<description>A bean that manages Grails plugins</description>
<property name="grailsDescriptor" value="/WEB-INF/grails.xml" />
<property name="application" ref="grailsApplication" />
</bean>
<bean id="grailsConfigurator" class="org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator">
<constructor-arg>
<ref bean="grailsApplication" />
</constructor-arg>
<property name="pluginManager" ref="pluginManager" />
</bean>
<bean id="grailsResourceLoader" class="org.codehaus.groovy.grails.commons.GrailsResourceLoaderFactoryBean">
<property name="grailsResourceHolder" ref="grailsResourceHolder" />
</bean>
<bean id="grailsResourceHolder" scope="prototype" class="org.codehaus.groovy.grails.commons.spring.GrailsResourceHolder">
<property name="resources">
<value>classpath*:**/grails-app/**/*.groovy</value>
</property>
</bean>
<bean id="characterEncodingFilter"
class="org.springframework.web.filter.CharacterEncodingFilter">
<property name="encoding">
<value>utf-8</value>
</property>
</bean>
<jaxws:server id="jaxwsService" serviceClass="at.pdts.cxf.HelloWorld" address="/hello">
<jaxws:serviceBean>
<bean class="at.pdts.cxf.HelloWorldImpl">
<property name="halloService"><ref bean="halloService"></ref></property>
</bean>
</jaxws:serviceBean>
</jaxws:server>
</beans>
HelloWorldImpl.groovy
package at.pdts.cxf
import javax.jws.WebService
#WebService(endpointInterface = "at.pdts.cxf.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
def halloService // inject HelloService. Initialize this bean via applicationContext.xml
public String sayHi(String text) {
return "hello " + halloService.scream(text)
}
}
HelloService.groovy
class HalloService implements InitializingBean{
static transactional = false
String scream(String text) {
text.toUpperCase()
}
// methods gets not called, so service bean is not initialized at the ws creation time
void afterPropertiesSet() {
println "------> initializing bean HalloSerivce <--------
}
}
It seems that at the moment of the jaxwsService initialization the helloWorld service bean is not available.

This needs to point to something:
<ref bean="helloWorld">
Do you have something like this defined:
<bean id="helloWorld" class="at.pdts.cxf.HalloServiceImpl" />
That error means that Spring could now find a spring bean with the alias "helloWorld."
Perhaps posting your entire spring.xml and the java code to HelloWorldImpl would help.
EDIT: Your config confirms my theory.
<ref bean= says "inject something else here". But you have not defined that bean, hence the exception No Such Bean Definition. Furthermore, I was able to make your code work by creating my own implementation of HalloService (HalloServiceImpl) with a custom scream method that returned a blank string. Then I added it to the spring configuration: <bean id="helloWorld" class="at.pdts.cxf.HalloServiceImpl" />
EDIT #2: Another way to make it work is by eliminating HalloService:
<jaxws:server id="jaxwsService" serviceClass="at.pdts.cxf.HelloWorld" address="/hello">
<jaxws:serviceBean>
<bean class="at.pdts.cxf.HelloWorldImpl" />
</jaxws:serviceBean>
</jaxws:server>
</beans>
HelloWorldImpl.groovy
package at.pdts.cxf
import javax.jws.WebService
#WebService(endpointInterface = "at.pdts.cxf.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
public String sayHi(String text) {
return "hello scream!" + text
}
}
Basically your choices are: Provide Spring an implmentation of HalloService, or don't reference it in your Spring.xml.
EDIT #3: There is a misunderstanding around the purpose of InitializingBean:
From the javadoc:
InitializingBean Interface to be implemented by beans that need to
react once all their properties have been set by a BeanFactory: for
example, to perform custom initialization, or merely to check that all
mandatory properties have been set.
Implementing InitializingBean just means that afterPropertiesSet() will be called. It does not mean the Spring will automatically add this bean to your Spring Config. You still must declare the bean in your spring configuration with this line:
<bean id="halloService" class="at.pdts.cxf.HalloService" />

I missed this the first time I read your question but you are defining your bean in applicationContext.xml. When I was making a test case for your question, I was putting my bean definition in grails-app/conf/spring/resources.xml. Try creating that file and putting the following into it:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!--create the bean for the service, link to groovy service bean -->
<jaxws:server id="jaxwsService" serviceClass="at.pdts.cxf.HelloWorld" address="/hello">
<jaxws:serviceBean>
<bean class="at.pdts.cxf.HelloWorldImpl">
<property name="halloService" ref="halloService" />
</bean>
</jaxws:serviceBean>
</jaxws:server>
</beans>
As a side note, you can find more information about integrating Grails and CXF here.

Related

why #autowired is not working when I access a bean

When I access a bean from spring bean configuration file using BeanFactory like this:
public class Person {
private String id,address;
#Autowired
private Customer customer;
//setters & getters
}
and bean configuration file
<bean name="person" class="com.ram.spring.model.Person"></bean>
<bean class="com.ram.spring.model.Customer">
<property name="email" value="ram#adp.com"></property>
<property name="name" value="Ram"></property>
</bean>
here is the executor class
public class PersonExecutor {
public static void main(String[] args) {
BeanFactory context = new XmlBeanFactory(new ClassPathResource("Spring.xml"));
Person person = (Person)context.getBean("person");
System.out.println(person.getCustomer());
}
}
when I execute this, I got null.is BeanFactory not supported for annotations?? any ideas??
Approach 1: Include below code in your xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Remaining bean declaration -->
</beans>
Approach 2: Remove #Autowired and inject customer in your xml file only.
<bean name="person" class="com.ram.spring.model.Person">
<property name="customer" ref="customer"></property>
</bean>
<bean name="customer" class="com.ram.spring.model.Customer">
<property name="email" value="ram#adp.com"></property>
<property name="name" value="Ram"></property>
</bean>
You have to use AnnotationConfigApplicationContext or
you have to add to yor Spring.xml to activate the annotation scan.
As #jens suggested
you should active annotation scan
<context:component-scan base-package="package_path">
</context:component-scan>
<context:annotation-config />
hope that helped
Why doesn't it work?
When using Spring with an XML context, using annotations is not activated by default. This means #Autowired, #Transactional, #PostConstruct and any other annotation you will use will simply not be exploited.
How do I fix it?
To make Spring aware of annotations, you need to add the following line:
<context:annotation-config />
Thus, Spring will search for annotations in the beans it creates and process them accordingly.
This requires activating the context namespace. At the top of your context, make sure you have all context related links and arguments1:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Your context -->
</beans>
You do not need <context:component-scan /> in your case. This would be useful if you used full-annotation context (e.g. classes annotated with #Component). See the difference between <context:annotation-config /> and <context:component-scan /> in this answer.
Alternate solution
As Naman Gala suggested, you could also drop #Autowired completely and inject all dependencies in XML. See the related answer for more details.
1 This includes the xmlns:context attribute (xmlns = XML NameSpace) and two URLs in xsi:schemaLocation.

Bean property 'channelIdentifierMap' is not writable or has an invalid setter method

I'm using Spring integration 4.0 and I tried to create a payloadTypeRouter object that has 2 message channels - one for String payloads and one for Integer payloads. I'm trying to do so by the following java code:
package MessageExamples;
import org.springframework.messaging.Message;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.router.PayloadTypeRouter;
public class Test {
public static void main(String[] args) {
QueueChannel q_channel1=new QueueChannel();
QueueChannel q_channel2=new QueueChannel();
ApplicationContext ctx= new ClassPathXmlApplicationContext("SpringIntegration.xml");
PayloadTypeRouter r= (PayloadTypeRouter) ctx.getBean("payloadTypeRouter");
}}
With the following configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd">
<bean id="payloadTypeRouter"
class="org.springframework.integration.router.PayloadTypeRouter">
<property name="channelIdentifierMap">
<map>
<entry key="java.lang.String" value-ref="stringChannel"/>
<entry key="java.lang.Integer" value-ref="integerChannel"/>
</map>
</property>
</bean>
<int:channel id="stringChannel"/>
<int:channel id="integerChannel"/>
</beans>
When I try to run it I get the following error message:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'payloadTypeRouter' defined in class path resource [SpringIntegration.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'channelIdentifierMap' of bean class [org.springframework.integration.router.PayloadTypeRouter]: Bean property 'channelIdentifierMap' is not writable or has an invalid setter method.
I've noticed that AbstractMessageRouter doesn't contain a map setter in Spring Integration version 4.0 although it has one in previous versions. How can I configurate this kind of router?
I think that you don't need the last channels definitions. According to the docs, you only need:
<bean id="payloadTypeRouter"
class="org.springframework.integration.router.PayloadTypeRouter">
<property name="channelIdentifierMap">
<map>
<entry key="java.lang.String" value-ref="stringChannel"/>
<entry key="java.lang.Integer" value-ref="integerChannel"/>
</map>
</property>
</bean>
Or, an equivalent definition:
<int:payload-type-router input-channel="routingChannel">
<int:mapping type="java.lang.String" channel="stringChannel" />
<int:mapping type="java.lang.Integer" channel="integerChannel" />
</int:payload-type-router>
The property was renamed to channelMapping several years ago (in 2.1); I have opened a JIRA Issue to fix the documentation.
Thanks for pointing this out.

Mbean JMX Spring Framework

I have a web application which has more than 40 Mbean. I used Spring Framework.
I am doing good and its working well. But i have 40 Mbean, so want to generalize the thing.
#Component
#ManagedResource(objectName="ProjectCache:name=XMBean", log=true, logFile="jmx.log")
public class XMBean extends AbstractCacheMBean<String, XCO, XCache> {
#ManagedOperation(description ="ProjectCache XCO key")
#Override
public List<String> showAllKeys(){
return super.getKey();
}
#ManagedOperation(description ="ProjectCache XCO")
public List<String> showAllElements(){
return super.findAll();
}
#Override
public XCache getCache() {
return getFacadeCache().getXCache();
}
#ManagedOperation(description ="ProjectCache XCO by key)
#Override
public String ShowbyKey(String key) {
return super.findbyKey(key);
}
}
Now i have Same way Class YMbean, AMBean and so.
I configured the Spring in application mbean.xml.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/beans"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd">
<!-- this bean must not be lazily initialized if the exporting is to happen -->
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="server" ref="mbeanServer"/>
<property name="assembler" ref="assembler" />
<property name="namingStrategy" ref="namingStrategy" />
</bean>
<bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
<!-- will create management interface using annotation metadata -->
<bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource" />
</bean>
<!-- will pick up the ObjectName from the annotation -->
<bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
<property name="attributeSource" ref="jmxAttributeSource" />
</bean>
<bean id="xMBean"
class="in.projet.business.mbean.XMBean">
<property name="memoryCache" ref="repository" />
</bean>
And same way i am going to preapre YMbean Class and in xml going to initialise.
What should i do that not require modification in XML Whatsoever or number of class i create ,dont require to update XML.
property is same in all Mbean which i am going to use.
All ideas or input are welcome.
Thanks
Remove all of your configuration and replace with the use of the namespace and only once. Also your MBeans are #Components so you can simply scan for them. Which only would leave you with the following lines of xml
<context:component-scan base-package="in.projet.business.mbean" />
<context:mbean-export/>
Or if you want to keep your current configuration instead of the namespace replace it at least with the following and remove all other beans. This enables autodetection of MBeans in your application context (this is basically the same as the <context:mbean-export /> does.
For more information I strongly suggest the JMX chapter of the reference guide.

Testing a service with mockito, ioC with autowiring

I'm trying to test a service with Mockito and testNG, but i have a couple of doubts. It's necessary create get/set to inject service, if service is declaredd like this:
#Autowired(required = true)
protected ITipService serveiTip;
when I'm trying to clean and package with maven I found this exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'consultaDeutes' defined in URL
[file:/D:/workspaceGPT/GPT/gpt.ui/target/test-classes/applicationContext-gui-deutes-Test.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'serveiTip' of bean class [cat.base.gpt.ui.ConsultaDeutesTest]: Bean property 'serveiTip' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
I believe that with autowiring get/set will be not necessary.
this is my test-context:
?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mockito="http://www.mockito.org/spring/mockito"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.mockito.org/spring/mockito https://bitbucket.org/kubek2k/springockito/raw/tip/springockito/src/main/resources/spring/mockito.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<context:component-scan base-package="cat.base.gpt.ui" />
<!-- mock del serveis que podem atacar per solicitar info -->
<mockito:mock id="serveiSubjecte" class="cat.base.tip.service.ISubjectesService"/>
<mockito:mock id="serveiTip" class="cat.base.tip.service.ITipService"/>
<mockito:mock id="serveiGpt" class="cat.base.gpt.domini.service.IGptService"/>
<mockito:mock id="sessio" class="cat.base.baseframe.session.IBaseSession"/>
<mockito:mock id="usuari" class="cat.base.baseframe.user.IBaseUser"/>
<!--
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:cat/base/bfp/ui/applicationResources" />
</bean>
-->
<bean name="consultaDeutes" class="cat.base.gpt.ui.ConsultaDeutesTest">
<property name="serveiTip" ref="serveiTip"/>
<property name="serveiGpt" ref="serveiGpt"/>
</bean>
</beans>
ApplicationContext:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mockito="http://www.mockito.org/spring/mockito"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.mockito.org/spring/mockito https://bitbucket.org/kubek2k/springockito/raw/tip/springockito/src/main/resources/spring/mockito.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<context:component-scan base-package="cat.base.gpt.ui" />
<!-- mock del serveis que podem atacar per solicitar info -->
<mockito:mock id="serveiSubjecte" class="cat.base.tip.service.ISubjectesService"/>
<mockito:mock id="serveiTip" class="cat.base.tip.service.ITipService"/>
<mockito:mock id="serveiGpt" class="cat.base.gpt.domini.service.IGptService"/>
<mockito:mock id="sessio" class="cat.base.baseframe.session.IBaseSession"/>
<mockito:mock id="usuari" class="cat.base.baseframe.user.IBaseUser"/>
<!--
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:cat/base/bfp/ui/applicationResources" />
</bean>
-->
<bean name="consultaDeutes" class="cat.base.gpt.ui.ConsultaDeutesTest"/>
<!-- WITH OUT PROPERTIES!!-->
</beans>
Using #Autowired will make spring automatically inject a matching bean into that field. Thus it is no longer required to define the "consultaDeutes" bean in the xml. If you'd like to use the xml definition, I believe you should define a setter for each property that you are trying to inject, eg: serveiTip, serveiGpt.
Using #Autowired in your test might require 2 additional annotation on the definition of your test class:
#ContextConfiguration(value = "/myContext.xml")
//#RunWith(SpringJUnit4ClassRunner.class) This is JUnit specific
#ActiveProfiles("dev")
public class TestCompareService {
#Autowired(required = true)
protected ITipService serveiTip;
....
}
I actually made a mistake pasting the #RunWith annotation specific for JUnit. For TestNG you can lookup this link. Apologies

Spring MongoDB and Apache Shiro

I am attempting to use Apache Shiro with Spring and MongoDB. I am using Spring Data Repositories which are autowired. I have created my own custom realm for Shiro which uses a Spring Data repository to talk to Mongo:
public class PlatformRealm extends AuthorizingRealm {
#Autowired(required = true)
protected UserRepository userRepository = null;
#Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
...
}
}
The problem I'm seeing is the userRepository isn't being autowired. I get the following line in my console output referring to the PlatformRealm:
INFO org.springframework.web.context.support.XmlWebApplicationContext - Bean 'platformRealm' of type [class com.resonance.platform.core.security.PlatformRealm] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
This is because of the Apache Shiro ShiroFilterFactoryBean. What is happening is this bean and all of its dependencies are being loaded up immediately when the container is started. It doesn't wait for my persistence beans to be initialized prior to resolving dependencies. This causes the repository reference to be null.
The following bean configurations are loaded via the contextConfigLocation parameter:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/web-platform-persistence.xml,
/WEB-INF/web-platform-services.xml
</param-value>
</context-param>
Services bean configuration:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<bean id="userSession"
class="com.resonance.platform.web.core.services.ShiroUserSessionService" />
<!-- Shiro (Security) -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/" />
<!-- The 'filters' property is not necessary since any declared javax.servlet.Filter
bean -->
<!-- defined will be automatically acquired and available via its beanName
in chain -->
<!-- definitions, but you can perform instance overrides or name aliases
here if you like: -->
<!-- <property name="filters"> <util:map> <entry key="anAlias" value-ref="someFilter"/>
</util:map> </property> -->
<property name="filterChainDefinitions">
<value>
# some example chain definitions:
/admin/** = passThruFilter, roles[admin]
/** = passThruFilter
</value>
</property>
</bean>
<bean id="passThruFilter"
class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" />
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- Single realm app. If you have multiple realms, use the 'realms' property
instead. -->
<property name="realm" ref="platformRealm" />
<!-- By default the servlet container sessions will be used. Uncomment
this line to use shiro's native sessions (see the JavaDoc for more): -->
<!-- <property name="sessionMode" value="native"/> -->
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor" />
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
<!-- Define the Shiro Realm implementation you want to use to connect to
your back-end -->
<!-- security datasource: -->
<bean id="platformRealm" class="com.resonance.platform.core.security.PlatformRealm" />
Persistence bean config:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<mongo:mongo id="mongo" />
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo" />
<constructor-arg value="platform" />
<property name="writeConcern">
<util:constant static-field="com.mongodb.WriteConcern.SAFE" ></util:constant>
</property>
</bean>
<mongo:repositories base-package="com.resonance.platform.core.data.repositories" />
User Repository:
package com.resonance.platform.core.data.repositories;
import org.bson.types.ObjectId;
import org.springframework.data.repository.CrudRepository;
import com.resonance.platform.core.entities.User;
/**
* A repository used to manage User entities.
* #author Kyle
*/
public interface UserRepository extends CrudRepository<User, ObjectId> {
/**
* Gets a user by the specified login.
* #param login
* #return
*/
User getByLogin(String login);
}
My question is, how can I get the userRepository dependency to resolved properly? I understand that the ShiroFilterFactoryBean has to be initialized before the other dependencies and whatnot, but there must be a way to get the userRepository dependency to be resolved.
EDIT: Added User Repository code.
I am running into the same problem described here.
I am noticing two spring factories.
from the dispacher-servlet.xml which loads #Service #Repository classes due to component-scan defined at an base package level so I can #Autowire Service class into Controller.
from application context doesn't seem to #Autowire classes marked as #Service because they are not loaded.
If I understand you right you should be able to create a subclass of ShiroFilterFactoryBean which implements org.springframework.beans.factory.InitializingBean. In InitializingBean.afterPropertiesSet() you would then add some code that gets the UserRepository and sets it to that field. Not the most elegant solution, but this looks like an exceptional case.
I've had this problem too. It has something to do with the order of bean initialization in the Spring container. The workaround is not to autowire the repository but have your realm implement ApplicationContextAware and get the needed beans straight from the context. It's not elegant, but it'll work.
I am not too sure if this is helpful, but you may check this question from me for an alternative solution.
But, the core issue probably still stays open.
Concrete problem explanation taken from ShiroFilterFactoryBean-and-a-spring-data-mongodb-realm:
The problem is that spring-data-mongodb requires a spring
ApplicationEventMulticaster to have been initialised before it can be
used.
ShiroFilterFactoryBean is a beanPostProcessor, and as such, during
initialisation, spring attempts to configure its realms(and hence my
realm and spring data mongo based userDao). it fails because
ApplicationEventMulticaster has not yet been created.
After I've tried several suggested ways to solve this problem, like the InitializingBean, ApplicationContextAware or BeanPostProcessor interfaces (each resulting in a premature invocation, hence before initializing my necessary service/repository stuff), I came up with the following solution:
Let spring create your shiro context without any automatic bean resolution to your services/repositories.
Let spring create your service/repository context, including mongodb
Create a simple class which will take care of your shiro-service coupling and configure it accordingly in your spring config. This class will be invoked after your shiro and service context has been successful set up.
To (1), sth. like this:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="filterChainDefinitions">
<value>
<!-- Your definitions -->
</value>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"
p:realm-ref="myShiroRealm" />
<bean id="myShiroRealm" class="com.acme.MyShiroRealm"
<!--no bean refs here-->
/>
To (2), sth. like this:
<bean id="myService" class="com.acme.MyService"
c:myRepository-ref="myRepository" />
...
<!-- Ask Spring Data to scan our repositories -->
<mongo:repositories base-package="com.acme.repository.impl.mongodb" />
To (3):
public class ShiroRealmServiceBridge {
public static void postInject( MyShiroServerRealm realm, MyService service ) {
realm.setService( service );
}
}
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"><value>com.acme.ShiroRealmServiceBridge</value></property>
<property name="targetMethod"><value>postInject</value></property>
<property name="arguments">
<list>
<ref bean="myShiroRealm" />
<ref bean="myService" />
</list>
</property>
Advantages:
It works xD
No additional burden/dependencies on your shiro stuff
Complete spring configuration and setup, resulting in a consistent state after initialization
Disadvantage:
One time overhead setup
May result in an inconsistent state, which will complain at runtime rather than at startup, if you forget or bump the glue-configuration
The ShiroFilterFactoryBean implements the BeanPostProcessor and, since it has dependencies on the security manager w/ its own dependencies on data stores, data access objects, etc. it can cause a whole slew of Bean X of type Y is not eligible for getting processed by all BeanPostProcessors messages.
The worst part is that it seems to be just a way to see the Filter implementations that Spring is instantiating in order to track and possibly inject properties into AuthorizationFilters.
Frankly I don't need that headache just for filter tracking, so I created a custom version that did not include the BeanPostProcessor. I'm now forced to manually wire in Filter implementations to the beans "filters" property, but at least I don't have to deal with that error and the questionable status of my security manager and related beans.

Categories

Resources