How to use javax.inject Provider<T> within spring xml configuration - java

I have a class called let's say A with such a setter:
//class A
#Inject
public void setAProvider(Provider<B> b)
{
this.b = b;
}
It works fine with javax.inject and annotation configuration when I want to have only one kind of A instance..
My problem is that I want to have two instances of class A, one with Provider<B1> and second with Provider<B2>. My question is how to express my requirements in Spring xml configuration?

Actually, it is briefly answered here, you need ProviderCreatingFactoryBean .
This is an example :
<bean id="a" class="a.b.b.A" scope="prototype">
<property name="xxx" value="15000"/>
</bean>
<bean id="b" class="a.b.b.B" scope="prototype">
<property name="zzz" value="-1"/>
</bean>
<bean id="providerOfA" class="org.springframework.beans.factory.config.ProviderCreatingFactoryBean">
<property name="targetBeanName" value="a"/>
</bean>
<bean id="providerOfB" class="org.springframework.beans.factory.config.ProviderCreatingFactoryBean">
<property name="targetBeanName" value="b"/>
</bean>
<bean id="barServiceA" class="a.b.c.BarService">
<property name="provider" ref="providerOfA"/>
</bean>
<bean id="barServiceB" class="a.b.c.BarService">
<property name="provider" ref="providerOfB"/>
</bean>

Related

Referencing a property of the current bean in Spring EL

I'd like to create a number of beans from a single class, all to be instantiated in the current application context, each based on prefixed properties in a properties file. I've given an example of what I'm trying to achieve. Any tips on how to do this without excessive code (e.g. without multiple classes, complicated factories, etc.) would be appreciated.
XML configuration:
<bean id="bean1" class="Mybean">
<property name="prefix" value="bean1"/>
</bean>
<bean id="bean2" class="Mybean">
<property name="prefix" value="bean2"/>
</bean>
<bean id="bean3" class="Mybean">
<property name="prefix" value="bean3"/>
</bean>
Properties File:
bean1.name=alfred
bean2.name=bobby
bean3.name=charlie
Class:
class Mybean {
#Value("${#{prefix}.name}")
String name;
}
Main Class:
public class Main {
#Autowired
List<MyBean> mybeans;
}
You can use PropertyPlaceholderConfigurer to set bean's name directly (instead of storing its prefix):
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="app.properties"/>
</bean>
<bean id="bean1" class="Mybean">
<property name="name" value="${bean1.name}"/>
</bean>
<bean id="bean2" class="Mybean">
<property name="name" value="${bean2.name}"/>
</bean>
<bean id="bean3" class="Mybean">
<property name="name" value="${bean3.name}"/>
</bean>

Common value configuration in Spring XML

I have several Spring beans in which one of the property value for all of them are same String value. Is there a way where I can define this String in XML at one place and refer it in all beans at property value settings?
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="someValue"></property>
<property name="commonProperty" value="commonValue"></property>
<bean id="nextBean" class="test.NextBean">
<property name="property2" ref="someValue"></property>
<property name="commonProperty" value="commonValue"></property>
How to set commonValue in a seperate place and refer it in both places?
Try like this.
<bean id="commonConfig" abstract="true">
<property name="commonField" value="CommonValue"></property>
</bean>
<bean id="class1" class="com.dataclass.Class1" parent="commonConfig">
<property name="field1" value="value1"></property>
</bean>
<bean id="class2" class="com.dataclass.Class2" parent="commonConfig">
<property name="field2" value="value2"></property>
</bean>
Class1 & Class2 having one common field name "commonField", parent attribute is use for this common purpose only.
In Spring this is called bean definition inheritance(this is not java class inheritance, above example Class1 & n Class not inheriting in their respective java file.)
For more detail, look at Spring doc's link.
I've never tried it before, but this should work
<bean id="commonProp" class="java.lang.String">
<constructor-arg name="original" value="yourString"></constructor-arg>
</bean>
Then, in every bean you need to reference it:
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="someValue"></property>
<property name="commonProperty" ref="commonProp"></property>
</bean>
You can define your string properties in some "init_constants.properties" file. Then you should load properties file in spring xml:
<bean id="properties"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:db.properties</value>
<value>classpath:mail.properties</value>
<value>classpath:init_constants.properties</value>
</list>
</property>
</bean>
And after that you can inject this properties using xml:
<bean id="somebean" class="test.SomeBean">
<property name="property1" ref="{$prop1}"></property>
<property name="commonProperty" value="commonValue"></property>
</bean>
or in code using #Value annotation:
#Value(value="${prop1}")
private String property1;
Well If commonValue is string then you can put it in properties file and read it using #Value annotation.

Spring global transaction committed after getting an element

I am using Spring and Hibernate with Jta Transactions, I have 2 databases, and I have a problem in a transactional method.
In this method I insert a lot of objects but I throws an exception to rollback the insertions, here the code works as I expected because the objects dont appear into the database.
But if I add a line in the method that get the objects of the same table, the objects are committed into the database.
I think that when I make a SELECT the objects are auto-committed, because the exception its thrown again and the objects persists into the database.
My xml and code:
dao.xml
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:configuracion_dao.properties" />
</bean>
<bean name="productosDAO" class="practica1.hibernate.HibernateProductosDAOImpl"
parent="abstractPracticaBean">
<property name="sessionFactory" ref="hibernateSessionFactory" />
</bean>
<bean name="tercerosDAO" class="${tercerosDAO.classname}" parent="abstractPracticaBean">
<property name="dataSource" ref="dataSourceDatos" />
</bean>
<bean name="auditoriaDAO" class="practica1.hibernate.HibernateAuditoriaDAOImpl" parent="abstractPracticaBean">
<property name="sessionFactory" ref="hibernateSessionFactory2" />
</bean>
<bean id="hibernateSessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSourceDatos" />
<property name="mappingResources">
<list>
<value>hibernate-mappings.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
<bean id="hibernateSessionFactory2"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSourceAuditoria" />
<property name="mappingResources">
<list>
<value>hibernate-mappings-auditoria.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
<bean name="dataSourceDatos" class="org.enhydra.jdbc.standard.StandardXADataSource">
<property name="driverName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="url" value="jdbc:derby:/tmp/datos.db;create=true" />
<property name="transactionManager" value="#{txManager.transactionManager}" />
</bean>
<jdbc:initialize-database data-source="dataSourceDatos"
ignore-failures="ALL">
<jdbc:script location="classpath:practica1/sql/creacion_derby.sql" />
<jdbc:script location="classpath:practica1/sql/datos.sql" />
</jdbc:initialize-database>
<bean name="dataSourceAuditoria" class="org.enhydra.jdbc.standard.StandardXADataSource">
<property name="driverName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="url" value="jdbc:derby:/tmp/auditoria.db;create=true" />
<property name="transactionManager" value="#{txManager.transactionManager}" />
</bean>
<jdbc:initialize-database data-source="dataSourceAuditoria"
ignore-failures="ALL">
<jdbc:script location="classpath:practica1/sql/creacion_auditoria_derby.sql" />
</jdbc:initialize-database>
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" value="#{jotm.transactionManager}" />
<property name="userTransaction" value="#{jotm.userTransaction}" />
</bean>
<bean id="jotm" class="org.objectweb.jotm.Jotm" destroy-method="stop">
<constructor-arg value="true" />
<constructor-arg value="false" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
bo.xml
<bean name="tercerosBO" class="practica1.impl.TercerosBOImpl"
parent="abstractPracticaBean" autowire="constructor">
</bean>
<bean name="productosBO" class="practica1.impl.ProductosBOImpl"
parent="abstractPracticaBean">
<property name="productosDAO" ref="productosDAO" />
<property name="auditoriaDAO" ref="auditoriaDAO" />
</bean>
aplicacion.xml
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames" value="mensajes" />
</bean>
<bean id="abstractPracticaBean" class="practica1.impl.AbstractPracticaBean" abstract="true">
<property name="messageSource" ref="messageSource"></property>
</bean>
<import resource="bo.xml" />
<import resource="dao.xml" />
Transactional method:
#Transactional
#Override
public void actualizaPrecio(double porcentaje) {
internalActualizaPrecio(porcentaje);
}
private void internalActualizaPrecio(double porcentaje) {
auditoriaDAO.insertAuditoria(getMessageSource().getMessage(
"mensaje.actualizar_productos", new Object[] { porcentaje },
null));
int i = 0;
auditoriaDAO.getAuditorias(); // Without this line its works like I expected
List<Producto> productos = productosDAO.getProductos();
for (Producto producto : productos) {
i++;
if (i > 3)
throw new UnsupportedOperationException(
"Error para que veamos las transacciones");
producto.setPrecio(producto.getPrecio().multiply(
new BigDecimal(porcentaje).divide(new BigDecimal(100))));
productosDAO.updateProducto(producto);
}
}
I realised that if I use auditoriaDAO.getAuditorias() the rollback only affects to Producto but if I use productoDAO.getProductos() the rollback only affects to Auditoria...
You may be mixing up flush and commit here: a SELECT statement usually flushes all previous SQL statements, in order to fetch up-to-date data (regarding the previous changes you made in the tx). It may be possible that before such a SELECT statement is done (the following DAO calls are made to the 2nd sessionFactory if I'm not mistaken), the exception exits the method without a flush. Hence no modification in database.
So the question is: are you sure you're rollbacking the tx effectively? I see you've annotated a private method: the proxy-based mechanism of Spring AOP don't handle that! You must annotate a public method and call it from outside the annotated method's class, due to this very proxy-based mechanism. See the "Method visibility and #Transactional" block in the documentation.
Another lead: you have 2 sessionFactories, so I assume you're using XA transactions/datasources: are you sure this part of the conf is OK?
Please check auditoriaDAO and productosDAO and search for other transactional annotation. I think a new transaction is created somewhere and the UnsupportedException rollbacks only the last transaction, and the parent transaction is committed. Hope I helped!
I have found two example. Please check it.
JOTM transactions in spring and hibernate
Access Multiple Database Using Spring 3, Hibernate 3 and Atomikos

Spring bean initialization with multiple-arg method

I would like to create the following Spring bean (a JMX monitor) which has a method setThresholds(Number highThreshold,Number lowThreshold).
Could I invoke the method (with two arguments) in the configuration? I don't want to write codes to invoke it.
<bean id="myMonitor" class="javax.management.monitor.GaugeMonitor" init-method="start">
<property name="observedObject">
<bean class="javax.management.ObjectName">
<constructor-arg value="test.jmx:name=testBean1" />
</bean>
</property>
<property name="observedAttribute" value="testProperty" />
<property name="granularityPeriod">
<bean class="java.lang.Float">
<constructor-arg value="1000" />
</bean>
</property>
</bean>
It is possible by using the MethodInvokingFactoryBean (Spring 4.x and 5.x) (It is not my idea, I just found it this forum: http://forum.springsource.org/archive/index.php/t-16354.html)
SomeClass someobject = new SomeClass();
someobject.set("String1","String2");
<bean id="someobject" class="SomeClass" />
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="someobject">
<property name="targetMethod" value="set">
<property name="arguments">
<list>
<value>String1</value>
<value>String2</value>
</list>
</property>
</bean>
I've never seen this done. The big idea of Spring is that you create and initialise straight forward beans. Therefore the only methods that will be called are therefore single argument Setters(...) and Constructors. The definition of what's supported will be in the following schema:
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
Your way around this problem is to get your bean to implement InitializingBean and call your method in the void afterPropertiesSet() method:
eg:
public void setHighThreadHold(Number highThreshHold) {}
public void setLowThreashHold(Number lowThreadHold) {}
public void afterPropertiesSet() {
setThresholds(highThreshold,lowThreshold);
}

With spring and hibernate, need clarification on how the datasource and session are wired

My DAO's are going to extend the HibernateDaoSupport class that spring provides.
Now I need to:
setup my database connection in web.xml
Tell spring I am using annotations for hibernate mapping?
wire the session to the HibernateDaoSupport object.
The doc's show a sample xml:
<beans>
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
</beans>
So the 'mydatasource' configures the connection to the database, and the mySessionFactory sets up the session.
What I am confused with is, where in the code are these beans being used?
I want to create a GenericDaoImpl that extendsHibernateDaoSupport. I will then create EntityDaoImpl that extend GenericDaoImpl.
Just confused as to where 'mydatasource' and 'mysessionFactory' are used internally. Shouldn't they both be properties to HibernateDaoSupport?
Shouldn't they both be properties to
HibernateDaoSupport?
Well, SessionFactory should. The DAO won't need the DataSource, since that's used internally by the SessionFactory. Your own code should have no need for the raw DataSource, and so should not have to be injected with it.
Your DAOs (which extend HibernateDaoSupport) need to injected with the SessionFactory bean, e.g.
public class DaoA extends HibernateDaoSupport {
// business methods here, that use getHibernateTemplate()
}
public class DaoB extends HibernateDaoSupport {
// business methods here, that use getHibernateTemplate()
}
<bean id="daoA" class="DaoA">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
<bean id="daoB" class="DaoB">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>

Categories

Resources