In a spring application,
Say Bean person is of scope prototype
and Bean address is of scope singleton
Class person
{
string name;
int age;
int rollno;
Address address;
// Getters & Setters
}
Class Address
{
int door_no;
string street_name;
// Getters & Setters
}
It is obvious that a new instance will be created for Person each time when requested.
now will a new instance be created for every request for Address or since it is referenced from person it will have the scope - prototype?
In sringBean.xml
<bean id="studentBeanId" class="com.saro.corespring.autowire.Person"
autowire="byName" scope="prototype">
<property name="name" value="saro" />
<property name="age" value="25" />
<property name="roll_no" value="101" />
</bean>
<bean id="addressBean" class="com.saro.corespring.autowire.Address" autowire="byType" scope="singleton">
<property name="door_no" value="10" />
<property name="street_name" value="Street Name" />
</bean>
Related
I have a test class created. I need to run the test file using spring dependency injection . I am using the XML method.
How to define a bean for Inventory in your XML configuration?
Testfile constructor:
public VendingMachineServiceLayerImplTest() {
Inventory testItem = new Inventory(2);
testItem.setItemName("Item2");
testItem.setCost(new BigDecimal("4.50"));
testItem.setNoOfItems(0);
VendingMachineDao dao = new VendingMachineDaoStubImpl(testItem);
VendingMachineAuditDao auditDao = new VendingMachineAuditDaoStubImpl();
VendingMachineChange change = new VendingMachineChange();
service = new VendingMachineServiceLayerImpl(dao, auditDao, change);
}
Bean Definition in applicationContext.xml
<bean id="dao"
class="mthree.vendingmachine.dao.VendingMachineDaoFileImpl"/>
<bean id="daoStub"
class="vendingmachine.dao.VendingMachineDaoStubImpl"/>
<bean id="change"
class="vendingmachine.dao.VendingMachineAuditDaoStubImpl"/>
<bean id="change" class="vendingmachine.dao.VendingMachineChange"/>
<bean id="serviceLayer"
class="vendingmachine.service.VendingMachineServiceLayerImpl">
<constructor-arg ref="dao"/>
<constructor-arg ref="auditDaoStub"/>
<constructor-arg ref="change"/>
</bean>
Inventory Class
public class Inventory {
private int itemNumber;
private String itemName;
private BigDecimal cost;
private int noOfItems;
public Inventory(int itemNumber){
this.itemNumber=itemNumber;
}
public int getItemNumber() {
return itemNumber;
}
//other getters and setters
}
How can i inject the constructor with the object? I have tried adding properties but the test error occurred as the properties couldn't parse.
Thanks in advance
Need to include the value that is in the constructor in the <constructor-arg> tag and other properties in the <property> tag in the Inventory Class as follows.
<bean id="daoStub"
class="mthree.vendingmachine.dao.VendingMachineDaoStubImpl"/>
<bean id="auditDaoStub"
class="mthree.vendingmachine.dao.VendingMachineAuditDaoStubImpl"/>
<bean id="change" class="mthree.vendingmachine.service.VendingMachineChange"/>
<bean id="inventory" class="vendingmachine.dto.Inventory">
<constructor-arg name = "itemNumber" value = "2"/>
<property name = "itemName" value = "Item2"/>
<property name = "cost" value = "5"/>
<property name = "noOfItems" value = "0"/>
</bean>
<bean id="dao" class="vendingmachine.dao.VendingMachineDaoStubImpl">
<constructor-arg ref = "inventory"/>
</bean>
<bean id="serviceLayer"
class="vendingmachine.service.VendingMachineServiceLayerImpl">
<constructor-arg ref="dao"/>
<constructor-arg ref="auditDaoStub"/>
<constructor-arg ref="change"/>
</bean>
I have found this subject that answered to what I was looking for :
how to pass values dynamically in config file
The thing is, when I try it, I have an Exception..
Error creating bean with name 'jobOperator' defined in class path resource [atlentic-Spring-Batch-common.xml]: Cannot resolve reference to bean 'jobExplorer' while setting bean property 'jobExplorer' [...]
Error creating bean with name 'connex' defined in class path resource [batch-calendar-context.xml]: Error setting property values;[...] Bean property 'dataSource' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
I'm trying to read a .ini file where I get DB info, then I would like to inject them into my XML datasource config.
Here is my xml,
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<beans:property name="driverClassName" value="${DB_DRIVER}" />
<beans:property name="url"
value="${DB_PROTOCOL}:#${DB_HOST}:${DB_PORT}:${DB_NAME}" />
<beans:property name="username" value="#{connex.user}" />
<beans:property name="password" value="#{connex.pass}" />
</beans:bean>
<beans:bean id="connex" class="com.sponge.bob.calendar.entity.CustomConnexion">
<beans:property name="dataSource" ref="dataSource" />
</beans:bean>
Then my CustomConnexiob.class where I use constructor to instantiate my attributs (it is not sexy, but I'm starting with SpringBatch) :
#Component
#Scope("step")
public class CustomConnexion {
public String user;
public String pass;
public String base;
#Autowired
private static final Logger LOGGER = LoggerFactory.getLogger(CustomConnexion.class);
public CustomConnexion() {
initConnexion();
}
public void initConnexion() {
IniReader reader = new IniReader();
setUser(reader.getProperty(Constants.MYCOMMON, Constants.USER));
setBase(reader.getProperty(Constants.MYCOMMON, Constants.BASE));
setPass(reader.getProperty(Constants.MYCOMMON, Constants.PASS));
}
/* getters and setters after this line (not printed here but they have the default name */
}
Is it possible to get this password and user dynamically using this way, I begin to lose my mind ?
Deinum,
thank you for your answer ! I tried to use UserCrendentialsDataSourceAdapter, but I didn't manage to make it work. But your observation about the scope make me try something I tried before writing this post.
Finally I used this :
<beans:bean id="connex" class="com.sponge.bob.calendar.entity.CustomConnexion">
</beans:bean>
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<beans:property name="driverClassName" value="${DB_DRIVER}" />
<beans:property name="url" value="${DB_PROTOCOL}:#${DB_HOST}:${DB_PORT}:${DB_NAME}" />
<beans:property name="username" value="#{connex.user}"/>
<beans:property name="password" value="#{connex.pass}"/>
</beans:bean>
and
#Component
#Scope("singleton") // <-- I changed this (it was "step" before)
public class CustomConnexion {
public String user;
public String pass;
public String base;
#Autowired
private static final Logger LOGGER = LoggerFactory.getLogger(CustomConnexion.class);
public CustomConnexion() {
initConnexion();
}
public void initConnexion() {
IniReader reader = new IniReader();
setUser(reader.getProperty(Constants.MYCOMMON, Constants.USER));
setBase(reader.getProperty(Constants.MYCOMMON, Constants.BASE));
setPass(reader.getProperty(Constants.MYCOMMON, Constants.PASS));
}
/* getters and setters after this line (not printed here but they have the default name */
}
my IniReader() just parse the .ini
I think you are getting username and password as null.
Remove calling initConnexion() from its constructor.
Add below annotation on top of initConnexion()
#PostConstruct
I am trying to call the Terminal_GetTicket stored procedure in my database but keep getting the following exception:
PropertyReferenceException: No property getTicket found for type TicketInfo
I have cross validated my configuration with a very simple test entity and everything seems to work fine, however for the actual case, something is wrong.
Here is my domain entity (TicketInfo):
#Entity
#NamedStoredProcedureQuery(name = "TicketInfo.getTicket", procedureName = "Terminal_GetTicket", resultClasses = TicketInfo.class, parameters = {
#StoredProcedureParameter(mode = ParameterMode.IN, name = "sys_id_game", type = Integer.class)})
public class TicketInfo {
#Id #GeneratedValue
private Long id;
private String idTicket;
private Integer externalTicketCode;
private Short sequenseAlert;
private Integer dlTimeStamp;
All the instance variables have their getters and setters properly defined and the stored procedure has a total of 5 output parameters matching the attributes of TicketInfo.
Furthermore, here is my repository interface:
public interface TicketInfoRepository extends CrudRepository<TicketInfo, Long> {
#Transactional(timeout = 5)
#Procedure
TicketInfo getTicket(Integer sys_id_game);
}
Also, here is my context.xml file (for Spring):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:repository="http://www.springframework.org/schema/data/repository"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd
http://www.springframework.org/schema/data/repository
http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd">
<context:component-scan base-package="ar.com.boldt.godzilla" />
<jpa:repositories base-package="xx.xxx.xxx.godzilla.business.dao" />
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${dataSource.show.sql}" />
<property name="generateDdl" value="false" />
<property name="database" value="SQL_SERVER" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<!-- spring based scanning for entity classes -->
<property name="packagesToScan" value="xx.xxx.xxx.godzilla.business.dao" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache" />
</bean>
<bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
</bean>
</beans>
And finally a watered-down version of the stored procedure itself:
ALTER PROCEDURE [Terminal_GetTicket](
#arg int
,#res int output
,#res2 int output
)
as
Declare #error int
select 0, 1, 2
RETURN #error
Now, whenever I try setting the #Autowired annotation, I get the exception mentioned above.
I remember that I have been struggling with the MS SQL stored procedures and spring-data-jpa. This is how I have been able to successfully run it:
Model:
#NamedNativeQueries({
#NamedNativeQuery(
name = "yourInternalName",
query = "EXEC [procedure_name] :param1, :param2",
resultClass = Foo.class
)
})
#Entity
public class Foo{
/* Fields, getters, setters*/
}
That's pretty straightforward. This approach is different though, you are not declaring procedures directly (that's also the reason why it doesn't have to work if you decide to change RDBS).
Then you have to extend your repository:
public interface FooRepositoryCustom {
Foo fancyMethodName(arg1, arg2);
}
And directly implement it:
public class FooRepositoryImpl implements FooRepositoryCustom {
#PersistenceContext
EntityManager entityManager;
#Override
public Foo fancyMethodName(arg1, arg2) {
Query query = entityManager.createNamedQuery("yourInternalName");
query.setParameter("param1", arg1);
query.setParameter("param2", arg2);
return query.getResultList();
}
Let's put it all together:
public interface FooRepository extends CrudRepository<Foo, Long>, FooRepositoryCustom {
}
Note that if you decide to return for example a List of Foo objects you only edit return value in your custom repository.
I followed SirKometas advice but I could not get it to work so I came up with something that worked for me and I think from syntax point of view is better. First create your entity class like below.
#NamedStoredProcedureQueries({//
#NamedStoredProcedureQuery(//
name = "MySP"//
, procedureName = "my_sp"//
, parameters = { //
#StoredProcedureParameter(mode = ParameterMode.IN, name = "arg", type = String.class)}//
, resultClasses = Foo.class)//})
#Entity
public class Foo {
Then the Implementation class of the repository would be:
#Component
public class FooRepositoryImpl implements FooCustomRepository {
#PersistenceContext
EntityManager entityManager;
#Override
public List<Foo> foo(String arg) {
Query query = entityManager.createNamedStoredProcedureQuery("MySP");
query.setParameter("arg", arg);
return query.getResultList();
}
}
The rest of the implementation is like the answer from SirKometa above. Think also that you have to create a EntityManager bean in your application for this to work.
In DAO:
private Map<Integer,String> departments = new LinkedHashMap<Integer, String>();
#Override
public List<DepartmentEntity> getAllDepartments() {
return this.sessionFactory.getCurrentSession().createQuery("from DepartmentEntity de order by LOWER(de.departmentname)").list();
}
#Override
public Map<Integer, String> loadDepartments() {
departments.clear();
for (DepartmentEntity de : getAllDepartments())
departments.put(de.getDepartmentid(), de.getDepartmentname());
return departments;
}
Its Working fine, but in spring creation of objects manually its bad code
private Map<Integer,String> departments;
So, how to inject map object of LinkedHashMap type from out side in my case ?.
I tried but i got exceptions like null pointer exception
Please any one help me..
<util:map id="myMap" map-class="java.util.LinkedHashMap" key-type="java.lang.Integer" value-type="java.lang.String"/>
<bean id="departmentDAOImpl" class="com.leadwinner.infra.assets.dao.DepartmentDAOImpl">
<property name="departments" ref="myMap"></property>
</bean>
You can do something like below:
eg.
class A{
private B b;
public setB(B b){
this.b = b;
}
public Map getMapFromA(){
return b.getMap();
}
}
class B{
private Map tmp;
public void setMap(HashMap t){
tmp.putAll(t);
}
public HashMap getMap(){
return tmp;
}
}
And in web.xml
<bean id="classB" class="default.B"/>
<bean id ="classA" class="default.A"/>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject"><ref local="classA"></property>
<property name="targetMethod"><value>setB</value></property>
<property name="arguments"><ref local="classB"/></property>
</bean>
Now spring beans are by default singleton scoped. So you can do the following.
function do(){
B b = ctx.getBean("classB");
b.setMap(someMap);
A a = ctx.getBean("classA");
a.getMapFromA();
}
I havent tried out the code but it will give you an idea I hope so. More details on MethodInvokingFactoryBean : here
And if you dont want to do it by Spring and if you want less efforts try using ThreadLocal to pass parameters.
Populate map in this way (using constructor injection):
<bean name="DAO" class="path.to.yourDAOClass">
<constructor-arg index="0">
<map>
<entry key="1" value="One" />
<entry key="2" value="Two" />
</map>
</constructor-arg>
<bean>
By default target class for <map /> is a LinkedHashMap, but you can change target class using a MapFactoryBean to construct your map object in this way by replace the <map /> tag with:
<bean class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="targetMapClass">
<value>java.util.HashMap</value>
</property>
<property name="sourceMap">
<map>
<entry key="1" value="One" />
<entry key="2" value="Two" />
</map>
</property>
</bean>
I ran in a strange behavior of db4o. When I persist an Object (implementing Serializable) with an attribute of Serializable[], the Array is only returned once from the store correctly then ever after only an Array with null elements.
I use db4o 7.12.
Edit
This is the POJO:
public class ResponseRowWrapper implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private long uuid;
private long responseUuid;
private Serializable[] row;
private long timestamp;
And this the config in spring:
<property name="transparentActivation" value="true" />
<property name="transparentPersistence" value="true" />
<property name="configurationCreationMode" value="NEW" />
<property name="lockDatabaseFile" value="false" />
<property name="callConstructors" value="true" />
<property name="exceptionsOnNotStorable" value="true" />
and in in the db4o Config Object:
configuration.common().objectClass(ResponseRowWrapper.class).cascadeOnUpdate(true);
Try passing the db4o configuration object a cascadeOnActivate(true) (that causes a cascaded load) or set a higher activation depth in db4o.
I solved it, but I can't tell what was wrong with a Serializable[] but it is not working, I need to use Object[] and just care by myself that there are only Serializables inside.