I'm getting a MyBatis NPE when I try to insert a record with a null primary key and then get the key value value back (an oracle trigger sets the key).
FooMapper interface:
...
public void insertFooObject (final Foo foo);
...
FooMapper.xml:
...
<insert id="insertFooObject" useGeneratedKeys="true" keyColumn="foo_id" keyProperty="fooId">
insert into foos (foo_id, gcor_id, registration_date)
values (#{fooId, jdbcType=NUMERIC}, #{gcorId, jdbcType=NUMERIC}, #{registrationDate, jdbcType=DATE})
</insert>
...
Here's the model:
public class Foo {
private final Integer fooId;
private final Integer gcorId;
private final Date registrationDate;
public Foo(final Integer fooId, final Integer gcorId, final Date registrationDate) {
this.fooId = fooId;
this.gcorId = gcorId;
this.registrationDate = registrationDate;
}
...
And here's the call:
...
Foo foo = new Foo(null, 229, null);
fooMapper.insertFooObject(foo);
...
fooMapper is injected by spring and can be used successfully for other SQL statements. When I pass in a number for fooId and registrationDate is null, everything works. When fooId is null (as shown), I get the error:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
Error updating database. Cause: java.lang.NullPointerException
The error may involve defaultParameterMap
The error occurred while setting parameters
SQL: insert into foos (foo_id, gcor_id, registration_date) values (?, ?, ?)
Cause: java.lang.NullPointerException
Here is my config file:
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
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="datasource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#......"/>
<property name="username" value="..."/>
<property name="password" value="..."/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource"/>
</bean>
<bean id="fooMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.foo.FooMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource" />
</bean>
</beans>
Any ideas how to correct this? I didn't have luck googling and thought I'd be okay by specifying jdbcType. Thanks!
I believe you are using useGeneratedkeys for oracle, which oracle does not supprot. GeneratedKeys are supported by mysql and postgress I believe. Instead use selectkeys to fetch the next value or as you are ok to pass the null value to fooId remove the useGeneratedKeys which is by default is false. You can get next value using sequence
<selectKey keyProperty="fooId"
resultClass="int">
SELECT nextVal('foo_id_seq')
</selectKey>
I found my problem in the model class (Foo.java):
public int getFooId() {
return fooId;
}
fooId is an Integer and not an int. By changing the getter return type to an Integer, I was able to insert a null primary key and get the trigger-created sequence id back
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>
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>
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.
I try to read an xml file as input for spring batch:
Java Class:
package de.example.schema.processes.standardprocess;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Process", namespace = "http://schema.example.de/processes/process", propOrder = {
"input"
})
public class Process implements Serializable
{
#XmlElement(namespace = "http://schema.example.de/processes/process")
protected ProcessInput input;
public ProcessInput getInput() {
return input;
}
public void setInput(ProcessInput value) {
this.input = value;
}
}
SpringBatch dev-job.xml:
<bean id="exampleReader" class="org.springframework.batch.item.xml.StaxEventItemReader" scope="step">
<property name="fragmentRootElementName" value="input" />
<property name="resource"
value="file:#{jobParameters['dateiname']}" />
<property name="unmarshaller" ref="jaxb2Marshaller" />
</bean>
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>de.example.schema.processes.standardprocess.Process</value>
<value>de.example.schema.processes.standardprocess.ProcessInput</value>
...
</list>
</property>
</bean>
Input file:
<?xml version="1.0" encoding="UTF-8"?>
<process:process xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:process="http://schema.example.de/processes/process">
<process:input>
...
</process:input>
</process:process>
It fires the following exception:
[javax.xml.bind.UnmarshalException: unexpected element (uri:"http://schema.example.de/processes/process", local:"input"). Expected elements are <<{http://schema.example.de/processes/process}processInput>]
at org.springframework.oxm.jaxb.JaxbUtils.convertJaxbException(JaxbUtils.java:92)
at org.springframework.oxm.jaxb.AbstractJaxbMarshaller.convertJaxbException(AbstractJaxbMarshaller.java:143)
at org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:428)
If I change to in xml it work's fine. Unfortunately I can change neither the xml nor the java class.
Is there a possibility to make Jaxb2Marshaller map the element 'input' to the class 'ProcessInput'?
I don't believe JAXB allows this. JAXB is a binding API, so it doesn't provide much in the way of customization. That being said, you can use XStream and provide aliases for what you need, allowing you to customize the mapping of XML to object however you want. You can see an XStream example here: https://github.com/spring-projects/spring-batch/blob/master/spring-batch-samples/src/main/resources/jobs/iosample/xml.xml
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>