RMI with Spring and AOP - java

I am trying to implement a Spring application with RMI and AOP. I am having problems with my server component. If the service interface which i want to expose does not extend Remote and the methods do not throw an RemoteException, I am getting the error:
UnknownAdviceTypeException: Advice object [org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#1f90645] is neither a supported subinterface of [org.aopalliance.aop.Advice] nor an [org.springframework.aop.Advisor]
if the interface extends Remote it works just fine with starting and so on.
My application.xml has only one bean declared:
<bean id="testService" class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="TestService" />
<property name="service" ref="testServiceImpl"/>
<property name="serviceInterface"
value="xxx.service.TestService" />
</bean>
My interface only has the #Transactional annotation, while the implementation has the #Service annotation.
In my client i get errors as well. Here i get an error of a not unique bean: found bean testService and testServiceImpl. My client.xml looks like this:
<bean class="xxx.start.Client">
<property name="testService" ref="testService"/>
</bean>
<bean id="testService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://localhost:1099/TestService"/>
<property name="serviceInterface" value="xxx.service.TestService"/>
</bean>
I followed this guide, but go the errors above. If you could help me id be very glad. If i run my JUnit test without RMI, its working all fine

i found out why it throws the error. it was because i had default-autowiring set to byType, but the RmiServiceExporter should have autowire=no

Related

Migrating from EJB with Spring to POJO

While migrating from EJB with spring to POJO , I read every where that just changing this configuration will work :
<bean id="sapFeedBean" class="org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean" lazy-init="true">
<property name="jndiName" value="ejb/sapBean" />
<property name="resourceRef" value="false" />
<property name="businessInterface" value="com.aa.inflightsales.sap.SapBusiness" />
<property name="lookupHomeOnStartup" value="false" />
</bean>
but how to do this , I am trying to create bean of the POJO class , but how can I define the business interface , as interface injection is not supported by spring.
Just define the business methods in this interface which should be implemented by the business class and when you need it just use a reference to the interface with the convenient annotation and the framework will inject the implementation.

NamedParameterJdbcTemplate and CGlib in Spring AOP

Hi All in my Spring application i have used AutoWired NamedParameterJdbcTemplate.
#Autowired
NamedParameterJdbcTemplate namedParametersJdbcTemplate;
in my rest-servlet.xml
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/mylfrdb"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<bean class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate" id="namedParameterJdbcTemplate">
<constructor-arg ref="jdbcTemplate"></constructor-arg>
</bean>
<bean class="org.springframework.jdbc.core.simple.SimpleJdbcCall" id="simpleJdbcCall">
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
It working fine.
No i have to use performance intercepter with Spring AOP.
So i added following thing in my rest-servlet.xml
<aop:config >
<aop:pointcut expression="#target(org.springframework.stereotype.Service)" id="allServices"/>
<aop:advisor pointcut-ref="allServices" advice-ref="perfMonitor"/>
</aop:config>
So i got error like this.
Can not set org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate field com.lfr.dao.impl.FlatAdvertiseDaoImpl.namedParametersJdbcTemplate to com.sun.proxy.$Proxy15
So i refered this question and tried to implement 2nd solution give is by using CGLIB and
<aop:config proxy-target-class="true" >
No i am getting this error
Could not generate CGLIB subclass of class [class org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
I had the exact same error message. I was using Spring 3.2.5.RELEASE version. After debugging and trying to repeat the problem with PetClinic example came out it was matter of Spring version. This problem didn't occur in Spring 4.1.1. Try to upgrade, maybe it works.

Configure a Repository on Spring via XML

I have been surfing on Internet for hours trying to find a good example to configure a Spring's repository by using the XML instead of annotations (#Repository).
I found some good stuff (Hibernate 3):
<!-- Hibernate interceptor to manage the session outside any transaction scope. -->
<bean id="hibernateInterceptor"
class="org.springframework.orm.hibernate3.HibernateInterceptor">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- The configuration DAO -->
<bean id="configurationDAO"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="configurationDAOTarget"/>
<property name="proxyInterfaces" value="org.itracker.persistence.dao.ConfigurationDAO"/>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>
<bean id="configurationDAOTarget"
class="org.itracker.persistence.dao.ConfigurationDAOImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
But it seems that Hibernate 4 does not support HibernateInterceptor any longer.
Have any of you experience with this issue? A good solution? There's no other option rather than using the annotation?
Thanks in advance.
All #Repository does is meta-annotate a #Component and let the org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor create an AOP proxy which does exception translation. At that level it's all Hibernate independent. The different implementations then understand their own exceptions and translate to the common Spring DataAccessException hierarchy.
In terms of doing it with XML, you'd have to somehow apply that proxy to the DAO beans you care about. Take a look at the reference manual for that, but it's going to be painful and not win you much.
For the sake of completeness, you can change the annotation from #Repository to something else, but as I read your question, you don't want to use annotations at all.

TransactionRequiredException: no transaction is in progress with Spring Data JPA

I looked around for similar problems but couldn't find a solution for this:
I have a Spring Data JPA application that whenever I try to do a trasaction I get javax.persistence.TransactionRequiredException: no transaction is in progress.
I believe it has something to do with the Transaction Manager or Entity Manager Factory, but can't put my finger on it.
The context files are here (latest checked in are here), but here is the part that matters:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceMySQL" />
<property name="persistenceUnitName" value="spring-jpa" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
<property name="database" value="MYSQL" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSourceMySQL"/>
</bean>
<bean id="dataSourceMySQL" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/dbname"/>
<property name="username" value="user"/>
<property name="password" value="pass"/>
</bean>
<jpa:repositories base-package="com.simplecash.dal.repository" />
A sample Repository is here and then created a Repository Factory here, which I'm not sure if I need...
Then use it here (line 34).
public void populateWithTestData() {
Bank bank = new Bank();
bank.setName("ContentName");
bank.setCode("ContentCode");
RepositoryFactory.getEntityManager().getTransaction().begin();
BankRepository bankRepository = RepositoryFactory.getRepository(BankRepository.class);
bankRepository.save(bank);
bankRepository.flush();
RepositoryFactory.getEntityManager().getTransaction().commit();
}
A couple of things are wrong above, but I I've tried fixing it and can't:
Begin and Commit transactions are explicit.
bankRepository should be #Autowired, but when I do that I get null. However, in this testcase it is Autowired and works.
Has anyone faced a similar problem and knows what's going on?
Thanks a ton for taking the time to read this. Hope the answer to this question will help other folks.
Both answer provided here offer good points (using injection to get the proxied beans and using transaction-annotations), however, I'm pretty sure that for the annotation-driven transactions to work (#Transactional), you need to add the following to your xml-configuration:
<tx:annotation-driven transaction-manager="transactionManager"/>
Also make sure to add the tx-namespace in your beans-tag:
<beans
<!-- SNIP, other namespaces -->
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
<!-- SNIP, other locations -->
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
I think that in your setup the Transactions are managed by JTA, so you can't explicitly start/stop them (i.e. em.getTransaction().begin() will not work). Try telling Spring that you want a certain method to be part of a (JTA managed) transaction via annotation , like:
#Transactional
public void populateWithTestData() {
//...
}
Begin and Commit transactions are explicit.
What Spring does with your repository beans ( e.g. BankRepository ), it creates a proxy around it, and then it is ready to be injected into other collaborators, which in your case is DatabaseManagerDAO. However if you create the object yourself like you do:
BankRepository bankRepository = RepositoryFactory.getRepository(BankRepository.class);
Instead of expected Spring's proxy ( that already does transaction management for you ), you are getting a simple object that is not aware of anything beyond it is immediate declaration.
What you need to do instead is to trust Spring to do the plumbing for you and just inject a bankRepository bean into a DatabaseManagerDAO (although I don't really think you need both DAO and Repository, since those terms really mean the same thing :)
Repository Factory here, which I'm not sure if I need...
No need for another abstraction. Just inject it as a bean to whatever component needs it.
bankRepository should be #Autowired, but when I do that I get null. However, in this testcase it is Autowired and works.
In a case where it works you run your test with AbstractTransactionalJUnit4SpringContextTests, which knows about 'bankRepository' bean, hence autowires it. In your DatabaseManagerDAO, I see neither autowiring nor a setter for the bankRepository, in fact you create it manually from the factory.
EDIT to answer comments
What jpa:repositories in your XML config really does => it scans the package and creates Spring beans for each component that is either annotated as #Repository or implements a Repository interface.
With that in mind, what you should do in order to use a BankRepository repository in your DatabaseManagerDAO is to inject it. You can do it via "autowiring":
#Service
public class DatabaseManagerDAO {
#Autowired
BankRepository bankRepository;
...
}
instead of manually creating it trough your factory.
Again, DatabaseManagerDAO in your case is probably a service ( #Service ), and not a DAO, but I'll leave it up to you to decide on that.
Notice that a DatabaseManagerDAO should also be loaded by Spring in order for the autowiring to work, so make sure it has one of the Spring annotations ( #Service / #Component ) when you package scan it ( e.g. <context:component-scan base-package="org.example"/> ).
I had a similar issue when combining spring-batch and spring-jpa. In my batch XML, I had this line:
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
which caused an error since JPA needs a PlatformTransactionManager.

Using a DAO on a Bean used by a Spring Scheduled Task

I'm developing a web application using Struts2 + Spring, and now I'm trying to add a scheduled task. I'm using Spring's task scheduling to do so. In my applicationContext I have:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
...
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
And then I have my DAO that uses this entityManagerFactory:
<bean id="dao" class="data.GenericDAO" />
So this works flawlessly within the web application. But now I have a problem when creating the scheduled task:
<task:scheduled-tasks scheduler="notifier">
<task:scheduled ref="emailService" method="sendMail" fixed-rate="30000" />
</task:scheduled-tasks>
<task:scheduler id="notifier" pool-size="10" />
<bean id="emailService" class="services.emailService" >
<property name="dao" ref="dao" />
</bean>
This executes the method sendMail on my emailService class every 30 seconds. And my emailService has the DAO injected correctly. The thing is that I can fetch objects with my DAO using the findById named queries, but when I try to access any property mapped by Hibernate, such as related collections or entities, I get an "LazyInitializationException: could not initialize proxy - no Session ". I don't know what's wrong, since I believe the scheduled task is being managed by Spring, so it should have no problem using a Spring managed DAO. I must say that I'm using the openSessionInView filter on my struts actions, so maybe I need something similar for this scheduled task.
Any help or suggestion will be appreciated, thanks!
Edit: Finally I found a way to fix this. I changed my regular Dao with one where I can decide when to start and commit the transaction. So before doing anything I start a transaction and then everything works OK. So I still don't know exactly what causes the problem and if someday I'll be able to use my regular DAO, for the moment I'm staying with this solution.
OpenSessionInView won't help you, because you don't have a web context. You need Spring's Declarative Transaction Management.
In most cases, what you need to do is just this XML:
<!-- JPA, not hibernate -->
<bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="myTxManager" />
<!-- without backing interfaces you probably also need this: -->
<aop:config proxy-target-class="true">
(Annotate your EmailService class as #Transactional to enable this)

Categories