MongoDb Factory with spring - java

I want to use MongoDB with Spring.
I'm trying to inject a MongoDbFactory in my DAO main class.
I dont want to use MongoTemplate because I need to use the MongoDB-Driver
When I try to run a jUnit Test, for test my DAO class, i get an NullPointerExeption on my factory....
I think it's a problem with my injection.
My app-config :
<bean id="mongoFactoryBean" class="org.springframework.data.mongodb.core.MongoFactoryBean">
<property name="host" value="127.0.0.1" />
<property name="port" value="27017"/>
</bean>
<bean id="mongoDbFactory"
class="org.springframework.data.mongodb.core.SimpleMongoDbFactory">
<constructor-arg name="mongo" ref="mongoFactoryBean" />
<constructor-arg name="databaseName" value="agence_voyage" />
</bean>
<bean id="dao" class="dao.daoImpl.DaoImpl">
<property name="mongoFactory" ref="mongoDbFactory" />
</bean>
my DAO class :
public class DaoImpl implements Dao {
private MongoDbFactory mongoFactory;
private DB db;
#Required
public void setMongoFactory(MongoDbFactory myMongoFactory){
this.mongoFactory= myMongoFactory;
}
//TODO development mongodb://localhost
public void connect() throws UnknownHostException {
try{
this.db = mongoFactory.getDb("agence_voyage"); //NullPointer here
}
catch(DataAccessException d){
System.out.println(d);
}
}
public int getVoyageCount(String collection) {
DBCollection col = db.getCollection(collection);
return (int) col.count();
}
}
And then my little test :
public class TestDao {
#Test
public void test() {
Dao test = new DaoImpl();
try {
test.connect();
} catch (UnknownHostException e) {
System.out.println(e);
assertTrue(false);
}
assertTrue(test.getVoyageCount("voyage")== 1);
}
}
Have you got any solution ?
I'm sure it's an idiot error but I don't find it !
Thanks in advance !

It doesn't seem like your test is in any way connected to the Spring context. You actually create the object yourself instead of getting a Spring managed bean
Dao test = new DaoImpl();
Why would Spring do anything to this object?
Add these annotations to your class
#ContextConfiguration(locations = "yourfile.xml")
#RunWith(SpringJUnit4ClassRunner.class)
and inject the DaoImpl bean directly.
#Autowired
private Dao test;
Then use that in your test.
Read the chapter on unit testing in the Spring documentation.

Related

Transaction rollback does not work in spring

Basically, i have a Sampleapiclass class in which some files are retrieved into a list and the list is looped and for each file performAction is called. if a file fails validation, i want the transaction to roll back. The problem is, i tried annotating with rollback, but even if one file validation fails, transaction is not rolled bak.eg. file 1, succeeds, gets inserted, file 2 fails, but the file 1 is in the database. Any idea what might be wrong ?
As an additonal note, Sampleapiclass is initialied from the main method , may be it has somethin to do that that ?
f.eks: from main class
class MainClass
{
public static void main(String[] args)
{
ApplContext ctx = new ClassPathxmlApplicationContext("application-context.xml");
MainClass app = ctx.getBean(MainClass.class);
app.run(args);
}
void run()
{
Sampleapiclass api = new Sampleapiclass();
DaoClass dao = new Sampleapiclass();
api.apimethod(dao)
}
}
class Sampleapiclass
{
void apimethod(Dao daoclass)
{
serviceClass serviceClass = new ServiceCLass(daoclass);
List<String> files = filesFromSomewhere
for (String file: filesFromSomewhere)
{
try
{
serviceClass.performAction(file);
}
catch(Exception e)
{
}
}
}
}
class serviceClass
{
private final Dao daoclass;
public serviceClass(DaoClass daoclass)
{
this.daoclass = daoclass;
}
#Transactional(rollbackFor=Exception.class)
void performAction(String file) throws CustomException
{
dovalidation(file); // this method can throw CustomExeption if validation fails
daoclass.insert(file)
}
dovalidation(String file) throws CustomExeption
{
if (file.endsWith("somethng") throw new CustomExeption();
}
}
class dao
{
void insert(String file)
{
getNamedParameterJdbcTemplate().update(parameters);
}
}
Contents of app contetxt:
<bean class="Configbean class />
<bean id="dataSource" class="org.springframework.jdbc.datasource.SingleConnectionDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="${main.db.uri}"/>
<property name="username" value="${main.db.username}"/>
<property name="password" value="${main.db.password}"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
The problem is that #Transactional works with AOP. AOP doesn't work on inclass method calls (due to Proxying). Try throwing an exception inside of your #Transactional for it to work or call a method outside of your class also marked with #Transaction(propagation = Propagation.SUPPORTS)
also don't forget #EnableTransactionManagement over your #Configuration class
helpful resource https://javamondays.com/spring-transactions-explained/

Why #Autowired didn't work in static method

I found many solutions to this issue, and choose the below one.
But it still gets NullpointerException, what's wrong?
A Class
#Component
public class A {
private static Foo foo;
#Autowired
public void setFoo(Foo foo) {
A.foo = foo;
}
public static someFunction() {
foo.doSomething();
}
}
B Class
#Service
public class B {
public void someFunction() {
A.someFunction();
}
}
You cannot auto-wire static properties in Spring, Static fields are instantiated during class load as they are the properties of the class while auto wired attributes work after spring initializes the beans.
Although you may use MethodInvokingFactoryBeanin Spring to achieve what you wanted.
some example would be in XML as below
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="foo.bar.Class.setTheProperty"/>
<property name="arguments">
<list>
<ref bean="theProperty"/>
</list>
</property>
</bean>
Edit :- without XML
inside your #Configuration class
do
#Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setStaticMethod("MyClass.staticMethod");
return methodInvokingFactoryBean;
}
let me know in case you need more help.

spring AOP with ProxyFactoryBean not working

Please find the class structure as below and help to find anything missing here.
Unable to get the SOP mentioned in the before method.
public class HijackBeforeMethod implements MethodBeforeAdvice {
#Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("BEFORE METHOD CALL : additional concern before actual logic");
System.out.println("Method : " + arg0);
}
}
The Main class as below
#RestController
public class A {
#Autowired
Dao b;
...
b.print(); //This should call the before method
}
The Dao class as below
Public class DaoImpl implements Dao{
#Autowired
Datasource ds
public void print(){
.....
}
}
the rest-servlet.xml context file entries as below
<bean id="hijackBeforeMethodBean" class="com.scb.cadm.aop.HijackBeforeMethod" />
<bean id="b" class="DaoImpl"></bean>
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">/>
<property name="target" ref="b"></property>
<property name="interceptorNames">
<list>
<value>hijackBeforeMethodBean</value>
</list>
</property>
</bean>
I found the issue..
Instead of
#Autowired
Dao b;
I have use the proxy bean
#Autowired
Dao proxy;

Using custom timeout in Spring transaction management

I have several methods with spring #Transactional in my project as following:
#Transactional(value = "sys.tx.mngr", propagation = Propagation.REQUIRES_NEW)
public void addMember(InputParam input)
{
// do somthing...
}
#Transactional(value = "sys.tx.mngr", propagation = Propagation.REQUIRES_NEW)
public void blockMember(InputBlockParam param)
{
// do somthing...
}
Then I set different timeout per method as following:
#Transactional(value = "sys.tx.mngr", propagation = Propagation.REQUIRES_NEW,timeout = 40)
public void addMember(InputParam input)
{
// do somthing...
}
#Transactional(value = "sys.tx.mngr", propagation = Propagation.REQUIRES_NEW, timeout = 20)
public void blockMember(InputBlockParam param)
{
// do somthing...
}
I want in last step set timeout as configurable by a properties file but I don't know what.
Is there any solution for set timeout in spring Transactional annotaion configurable or dynamically?
EDIT:
I define sys.tx.mngr in spring context file as following:
<bean id="sys.tx.mngr" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>
<tx:annotation-driven transaction-manager="sys.tx.mngr" />
Or is there alternative way for define timeout in spring context file per method?
It can be done on following ways only :-
a) Using Reflection.
b) Using Instrumentation.
c) Using TransactionTemplate (Programatically transaction).
For (a) & (b) you can have your class like following :-
public class Test implements InitializingBean {
#Autowired
private Environment env;
public void afterPropertiesSet() throws Exception {
System.out.println("Sample prop 1 value : "+env.resolvePlaceholders("${prop1.value}"));
//Code to set/modify Transactional annotation "timeout"
// attribute values for all methods
}
}
Link on how to set/modify values can be found here
Modify field annotation value dynamically
Modify a class definition's annotation string parameter at runtime
For (c) you can have config like :-
public class MemberDaoImpl {
#Autowired
private Environment env;
#Autowired
private TransactionTemplate transactionTemplate;
public void addMember(InputParam input) {
transactionTemplate.setTimeout(Integer.parseInt(env.resolvePlaceholders("${addmember.timeout}")));
// do somthing...
}
}
<bean id="memberDao" class="com.xxx.impl.MemberDaoImpl">
<property name="transactionTemplate">
<bean class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="sys.tx.mngr" />
</bean>
</property>
</bean>
<bean id="sys.tx.mngr" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf"/>
</bean>

Spring annotation based SAP connector

I'm trying to move from a xml based config to java annotations
I need your help getting this to work:
Obviously I can't set the RemoteJco interface to my SapConnector but what can I do to get this xml-config working?
#Bean
public RmiProxyFactoryBean jcoPool(){
RmiProxyFactoryBean jcoPool = new RmiProxyFactoryBean();
jcoPool.setServiceUrl("rmi://localhost/CH");
jcoPool.setServiceInterface(RemoteJco.class);
jcoPool.setRefreshStubOnConnectFailure(true);
return jcoPool;
}
#Bean
public SapConnector SapConnector(){
SapConnector sapConnector = new SapConnector();
sapConnector.setJcoPool(jcoPool());
return sapConnector;
}
this in the XML-Config works just fine:
<!-- JCO-Pool RMI Service -->
<bean id="jcoPool" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://localhost/CH"/>
<property name="serviceInterface" value="com.itensis.jco.common.RemoteJco"/>
<property name="refreshStubOnConnectFailure" value="true" />
</bean>
<bean id="SapConnector" class="com.itensis.core.SapConnector">
<property name="jcoPool">
<ref bean="jcoPool" />
</property>
</bean>
this is my SAP-Connector
#Service
public class SapConnector {
#Autowired private RemoteJco jcoPool;
public RemoteJco getJcoPool() {
return jcoPool;
}
public void setJcoPool(RemoteJco jcoPool) {
this.jcoPool = jcoPool;
}
}
You have to make some changes on the jcoPool bean:
#Bean
public RemoteJco jcoPool(){
RmiProxyFactoryBean jcoPool = new RmiProxyFactoryBean();
jcoPool.setServiceUrl("rmi://localhost/CH");
jcoPool.setServiceInterface(RemoteJco.class);
jcoPool.setRefreshStubOnConnectFailure(true);
jcoPool.afterPropertiesSet();
return (RemoteJco) jcoPool.getObject();
}
Make sure that you return value has the same class as you used as service interface. And you have to call afterPropertiesSet() before calling getObject on the RmiProxyFacotoryBean instance.

Categories